//============================================================================================
/**
 * @file	pkthln_run.c
 * @brief	マラソン
 * @author	Nozomu Saito
 */
//============================================================================================

#include "pkthln_run.h"
#include "pkthln_run_local.h"
#include "../../pkthln_obj_common.h"
#include "../../poke_clact.h"
#include "../pkthln_clact.h"
#include "../pkthln_act_def.h"

#include "system/snd_tool.h"
#include "system/wipe.h"
#include "system/render_oam.h"
#include "system/fontproc.h"
#include "gflib/touchpanel.h"

#include "../../pkthln_comm_pack.h"
#include "../../poke_clact_move.h"

#include "../event_se_def.h"

#include "system/arc_util.h"

#include "run_comm.h"
#include "run_obj_pri.h"

#include "../../cmn_res.h"

#include "pkthln_run_sub.h"

#include "run_ai.h"

//成績作成用
#include "system/msgdata_util.h"
#include "msgdata/msg.naix"
#include "msgdata/msg_pokethlon.h"

#include "../pkthln_evt_info.naix"
#include "pkthev_run.naix"
#include "communication/wm_icon.h"


//同期待ち
#include "../../pkthln_frame_seq_def.h"	//for	FRAME_SEQ_CALLBACK_WAIT

// 構造体が想定のサイズとなっているかチェック
#ifdef PM_DEBUG
#ifdef _NITRO
SDK_COMPILER_ASSERT(sizeof(RUN_PARENT_DATA) == 36);
#endif
extern DEBUG_PKTHLN_WORK DebugPkthlnWk;
#endif		//PM_DEBUG

//デバッグ機能
#ifdef PM_DEBUG
//#define DEBUG_STAMINA_INF		//スタミナ無尽蔵
///#define DEBUG_HIT_CHECK_IGNORE	//障害物当たり判定無視
///#define DEBUG_MIN_TIME			//デバッグ短縮時間
#endif

#define RUN_HEAP_SIZE	(0x68000)

#define RUN_EVENT_POKE_NUM	(ENTRY_MAX*ENTRY_MEMBER_NUM_MAX)
#define SUB_ACT_MAX		(ENTRY_MEMBER_NUM_MAX*4 + 2 + 2 + 1 + 5)	//（アイコン+マーカー+ステート+ボール）*表示アイコン4 + ポケグラ2 + ポケグラ汗2 +時計1+タイム6
#define MAIN_ACT_MAX	(1+1+1+1+(RUN_EVENT_POKE_NUM*6)+OBST_NUM_MAX+4 + ENTRY_MAX)
//↑カウントダウン+ラストカウント+交代ボタン+LAP+チーム数*(ポケ+マーカ+影+ボール+ステート+煙)+障害物*30+ヒットエフェクト4+ペン3
#define ACT_MAX		(MAIN_ACT_MAX + SUB_ACT_MAX)
#define SUB_DISP_PAL_NUM	(3+2+2)		//アイコンパレット3+ポケグラｘ2+OBJ2
#define RUN_MAIN_OBJ_PALETTE_NUM	(2)			//OBJ

#define RUN_EVENT_OBJ_NUM	(RUN_EVENT_POKE_NUM + ACT_MAX )
#define RUN_EVENT_PAL_NUM	(RUN_EVENT_POKE_NUM + 1 + \
		RUN_MAIN_OBJ_PALETTE_NUM + SUB_DISP_PAL_NUM)	//ポケ12+共有リソース+メイン画面+サブ画面

#define START_POKE_POS_X	(80)
#define START_POKE_POS_Y	(INNER_OFS)
#define START_POKE_POS_Y_OFS	(8)
#define START_POKE_MARGINE	( (192-(START_POKE_POS_Y+24))/5 )
#define Y_LIMIT	(192-24)

#define PCLACT_TCB_PRIORITY	(0)

#define TOUCH_TIME_MAX	(255)
#define TOUCH_TIME_ACCEL	(30)

#define ACCEL_MAX	(11)
#define ACCEL_DIV	(8.0)
#define DECEL_COEF	(0.4)		//減速係数
#define ROUND_LEN	(1024.0)
#define ROUND_LEN_INT	(1024)
#define DISP_W		(256)

#define DISP_X_MIN	(-32)
#define DISP_X_MAX	(256+32)

#define CHG_BTN_W	(64)
#define CHG_BTN_H	(32)

#define BALL_UP_LIMIT	(-32 * FX32_ON
#define BALL_MOVE_SPEED	(20*FX32_ONE)
#define BALL_MOVE_COUNT	(20)

#define FATIGUE_START	(40.0)
#define STAMINA_INC	(0.5)
#define STAMINA_DEC	(0.5)

#ifdef DEBUG_MIN_TIME
#define GAME_TIME		(30)		//デバッグ短縮ゲーム時間
#else
#define GAME_TIME		(90*30)		//ゲーム時間1分30秒
#endif

#define CHG_BTN_X		(32)
#define CHG_BTN_Y		(16)

#define BOOST_OFS	(24 * FX32_ONE)

///#define FAT_ACL_COEF	(1.0)		//疲労時の衝突加速係数
///#define PNC_ACL_COEF	(1.0)		//気絶時の衝突加速係数

#define OBST_Y_LIMIT	(160)

#define HIT_EFFECT_NUM	(4)

#define HIT_FRAME_DMG		(6)		//ヒット後の硬直時間(あたられた方)
#define HIT_FRAME_ATK	(18)		//ヒット後の硬直時間(あたった方)

#define LAP_DISP_TIME	(60)	//ラップ表示タイム

//ＢＭＰ関連
#define	REC_FONT_PAL	(15)
#define WIN_CGX_BASE	(1)
#define WIN_REC_CGX	(WIN_CGX_BASE)
#define REC_BG	(GF_BGL_FRAME3_M)

#define	COL_N_WHITE	( GF_PRINTCOLOR_MAKE( 15, 14, 0 ) )		// フォントカラー：白

#define ROUND_MAX	(60)		//最大周回数
//↑一応、最大値を決めてますが、上画面の周回表記の小数点以下は、
//ポケモンの現在地から割り出しているので、
//99.9の表示のあとゴールラインを突破すると、99.0に戻ってしまいます。
//なので、99周に到達できないようなゲーム時間にする必要があります。
//現在ゲーム時間は２分となっており、
//最速で走っても、99周にとどかないようになっています。
//※追記：レコード無しの状態を0xffffで検出しているので、レコードが0xffffになると誤認が起きる
//また、レコードは2バイトで保存しているので、99ｘ1024=101376=0x18C00は実は保存できない・・・
//上記2点の理由により競技最高記録を60前後にしておかないと誤作動が起きるので99から60に変更

#define GAME_MAX_SPEED	(11)		//ゲーム内最大速度

#define SE_PLAYER_MINE		(PLAYER_SE_1)
#define SE_PLAYER_OTHERS	(PLAYER_SE_2)
#define SE_PLAYER_HIT		(PLAYER_SE_3)


#define RUN_COURSE_NUM		(10)

#define BACK_STRK	(16)

typedef enum {
	CHILD_CHG_NONE = 0,
	CHILD_CHG_UP_END,
	CHILD_CHG_DOWN_END,
}CHILD_CHG_STATE;

typedef enum {
	MOVE_STOP = 0,
	MOVE_NORMAL,
	MOVE_DASH,
	MOVE_MACH,
}MOVE_MODE;

typedef struct RUN_PARAM_tag
{
	int Power[5];
	int Stamina[5];
	int Accel1[5];
	int Accel2[5];
	int Panic[5];
	int Speed[5];
	int SpeedLow[5];
	int SpeedMat[5];
}RUN_PARAM;

typedef struct RUN_OBST_tag
{
	BOOL Valid;
	PKTHLN_ACT_PTR	ActPtr;
	u16 X;
	u8	Y;
	u8	Type;
}RUN_OBST;

typedef struct LAP_ACT_tag
{
	CLACT_WORK_PTR LapNum1Ptr;
	CLACT_WORK_PTR LapNum2Ptr;
	PKTHLN_ACT_PTR LapActPtr;
	u16	Timer;
	u16 StockLap;
}LAP_ACT;

typedef struct PKTHLN_RUN_tag
{
	GF_BGL_INI *bgl;
	GF_BGL_BMPWIN	Win;			// BMPウィンドウデータ
	int HeapID;
	//アクター
	PKTHLN_CLACT_CNT_PTR ActCntPtr;
	//交代ボタン
	PKTHLN_ACT_PTR	ChgBtnActPtr;
	//LAP
	LAP_ACT LapAct;

	RUN_POKE	Poke[ENTRY_MEMBER_NUM_MAX];

	TP_STATE	TpState[ENTRY_MEMBER_NUM_MAX];		//親が使う
	BOOL HoldPoke[ENTRY_MEMBER_NUM_MAX];			//親が使う

	u8 EndFlg;
	u8 StartCount;
	u8 Brake;
	u8 HitEffIdx;

	CMN_RES_CNT_PTR	CmnResCntPtr;
	POKE_ACT_CNT_PTR PokeActCntPtr;
	//ヒット
	PKTHLN_ACT_PTR	HitActPtr[HIT_EFFECT_NUM];

	RUN_AI_CONT_PTR AICntPtr;
	RUN_SUB_CNT_PTR SubDispCntPtr;

	//障害物データ
	int ParentObstData[OBST_NUM_MAX];
	int ObstData[OBST_NUM_MAX];
	RUN_OBST	Obst[OBST_NUM_MAX];

	u8 HitEff;
	u8 HitEffY;
	u16 HitEffX;

	u16 CommTime;			//通信する時間データ
	u16 PushSE;				//ボタン押下ＳＥ用

	u8 BtnSt[ENTRY_MEMBER_NUM_MAX];
}PKTHLN_RUN;


static void SetVramBank(void);
static void BgInit(GF_BGL_INI * ini);
static void SetGraphic(PKTHLN_RUN_PTR ptr);
static void SetObj( PKTHLN_CLACT_CNT_PTR pActCntPtr);
static void SetAct( PKTHLN_RUN_PTR ptr, PKTHLN_CLACT_CNT_PTR pActCntPtr);

static BOOL RUN_Func_Phase0(PKTHLN_PTR work, u8 *seq);
static BOOL RUN_Func_Phase1(PKTHLN_PTR work, u8 *seq);
static BOOL RUN_Func_Phase2(PKTHLN_PTR work, u8 *seq);

static void SetCommInfo(PKTHLN_RUN_PTR ptr, RUN_PARENT_DATA *parent);
static void CommMain(PKTHLN_PTR work);
static BOOL ControlMain(PKTHLN_PTR work);
static void SetDraw(PKTHLN_PTR work);

static BOOL CheckPokeTouch(PKTHLN_RUN_PTR ptr, const u8 inNetID, const u16 inX, const u16 inY);
static BOOL CheckChgBtnTouch(PKTHLN_RUN_PTR ptr, const u16 inX, const u16 inY);
static void MovePoke(PKTHLN_PTR work);
static void MovePokeHitFrame(PKTHLN_PTR work, PKTHLN_RUN_PTR ptr, RUN_POKE *run_poke);
static void CalcPokeDispPos(PKTHLN_PTR work,
							const u8 inMyNetID,
							RUN_POKE *inPokeList,
							COMM_EVENT_COMMON_DATA *commData);
static void CalcObstDispPos(PKTHLN_RUN_PTR ptr, const int inMyLen);

static void BallUpAnm(	RUN_SUB_CNT_PTR sub_ptr, RUN_POKE *run_poke, const VecFx32 *inTPos,
						const u8 inNetID, const u8 inRunPokeIdx,
						RUN_CHILD_DATA *outChildData,
						const BOOL inReqNpcMv, const BOOL inReqSubDemo);
static void BallDownAnm(RUN_POKE *run_poke, const VecFx32 *inTPos,
						const u8 inNetID, const u8 inRunPokeIdx, RUN_CHILD_DATA *outChildData,
						const BOOL inReqSend, const BOOL inReqSubDemo);
static void ChangeEndAnm(	RUN_POKE *run_poke,
							const u8 inNetID, const u8 inRunPokeIdx, RUN_CHILD_DATA *outChildData,
							const BOOL inReqSend, const BOOL inReqSubDemo	);
static void ChangeDemo(	RUN_SUB_CNT_PTR sub_ptr, RUN_POKE *run_poke, const VecFx32 *inSdwPos,
						const RUN_PARENT_DATA *inParent,
						const u8 inNetID, const u8 inRunPokeIdx,
						RUN_CHILD_DATA *outChildData,
						const BOOL inIsParent, const BOOL inReqSubDemo, const BOOL inIsNPC);
static void SetPokeParam(	PKTHLN_PTR work, const RUN_PARAM *inData,
							const u8 inNetID, const u8 inIdx, RUN_POKE *outPoke);

static u16 HitCheckObst(PKTHLN_RUN_PTR ptr, const HIT_RC inHitRc, const int inRange,
		const VecFx32 *inSrt, const VecFx32 *inEnd, VecFx32 *outVec);

static fx32 CalcT(const VecFx32 *inSrt, const VecFx32 *inEnd,
		const VecFx32 *inVrt , const fx32 inC);

static float GetMaxSpeed( RUN_POKE *poke, const u8 inRunPokeIdx );
static void AddSpeedVec(const VecFx32 *inSrcVec, const VecFx32 *inAddVec, VecFx32 *outDstVec);
static BOOL HitCheckPoke(PKTHLN_PTR work, RUN_POKE*	pPokeList, VecFx32 *outVec);
static void SetStateActPos(	const PKTHPOKE_PARAM *inParam,
							const VecFx32 *inSdwPos,
							PKTHLN_ACT_PTR pStateActPtr );
static void SetObstPriority(RUN_OBST *obst);
static void SetPokePriority(RUN_POKE *poke, const u8 inY, const BOOL inMine);
static void FillGoalLine(GF_BGL_INI *bgl, const int inLen);
static void DispLap(LAP_ACT *pLapAct, const u8 inLap);

static void CreateBmpWin( PKTHLN_RUN_PTR ptr );
static void SetRecordStr(PKTHLN_RUN_PTR ptr, const int inRound, const u16 inLen);

static void PlaySeDispCheck(const int inX, const int inSE, const BOOL inMine);

static void SetBtnState(PKTHLN_RUN_PTR ptr, const u8 inNetID, const BOOL inValid);

static void RecCallBack(PKTHLN_PTR work);

enum {
	BTN_ST_PUSH_OK,
	BTN_ST_PUSH_OK_FLASH,
	BTN_ST_PUSH_OK_PUSH,
	BTN_ST_PUSH_NG,
	BTN_ST_PUSH_NG_PUSH,
};

PKTHLN_FUNC RunFuncTbl[] = {
	RUN_Func_Phase0,
	RUN_Func_Phase1,
	RUN_Func_Phase2,
};

enum {
	RUN_SEQ_PHASE0,
	RUN_SEQ_PHASE1,
	RUN_SEQ_PHASE2,
};

#ifdef PM_DEBUG
static u8 debug_print = 0;
#endif

//--------------------------------------------------------------------------------------------
/**
 * 初期化関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
PTH_RC PE_RUN_InitFunc(PKTHLN_PTR work, void *pParam)
{
	PKTHLN_RUN_PTR ptr = PTFrame_GetEventWorkPtr(work);
	u8 seq = PTFrame_GetSubSeq(work);
	switch(seq){
	case 0:
		{
			int heap_id;
			sys_CreateHeap( HEAPID_POKETHLON, HEAPID_PT_RUN, RUN_HEAP_SIZE );
			heap_id = HEAPID_PT_RUN;
			sys_VBlankFuncChange( NULL, NULL );	// VBlankセット
			sys_HBlankIntrSet( NULL,NULL );		// HBlankセット

			GF_Disp_GX_VisibleControlInit();
			GF_Disp_GXS_VisibleControlInit();
			GX_SetVisiblePlane( 0 );
			GXS_SetVisiblePlane( 0 );

			//VRAMバンク割り当て
			SetVramBank();
			//アプリケーションメモリー
			ptr = PTFrame_AllocEventWork(work, sizeof(PKTHLN_RUN));
			MI_CpuClear8( ptr, sizeof(PKTHLN_RUN));

			//BGLアロケーション
			ptr->bgl = GF_BGL_BglIniAlloc(heap_id);

			//競技アプリ内共有データポインタのセット
			PTFrame_SetEvtShareDataPtr(work, ptr->ParentObstData, ptr->ObstData, sizeof(int)*OBST_NUM_MAX );

			//レコード表示ＢＧのセット
			PTFrame_SetRecBGMask(work, GX_PLANEMASK_BG3);

			{
				CHAR_MANAGER_MAKE cm;
				cm.CharDataNum = RUN_EVENT_OBJ_NUM;
				cm.VramTransAreaMain = 256*1024;
				cm.VramTransAreaSub = 16*1024;
				cm.heap = heap_id;

				//キャラ・パレットマネージャ初期化
				PKTHLN_OBJ_COMMON_InitCharPlttManager(	&cm,
														RUN_EVENT_PAL_NUM,
														heap_id,
														GX_OBJVRAMMODE_CHAR_1D_256K,
														GX_OBJVRAMMODE_CHAR_1D_32K);
			}

			// OAMマネージャーの初期化
			NNS_G2dInitOamManagerModule();

			// 共有OAMマネージャ作成
			// レンダラ用OAMマネージャ作成
			// ここで作成したOAMマネージャをみんなで共有する
			REND_OAMInit(
					0, 126,		// メイン画面OAM管理領域
					0, 32,		// メイン画面アフィン管理領域
					0, 126,		// サブ画面OAM管理領域
					0, 32,		// サブ画面アフィン管理領域
					heap_id);
			ptr->HeapID = heap_id;
		}

		//タッチフォントロード
		FontProc_LoadFont(FONT_TOUCH, ptr->HeapID);

		BgInit(ptr->bgl);

		//BMP
		CreateBmpWin(ptr);

		//下画面をメインにする
		sys.disp3DSW = DISP_3D_TO_SUB;
		GF_Disp_DispSelect();

		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 1:
		ptr->SubDispCntPtr = RunSub_Init( ptr->HeapID, ptr->bgl, work);
		ptr->AICntPtr = RunAI_Init(ptr->HeapID,
				ENTRY_MEMBER_NUM_MAX-PTFrame_GetPlayerNum(work), PTFrame_GetGameType(work));
		ptr->CmnResCntPtr = CmnRes_Init( ptr->HeapID,
				CMN_RES_ALL_BIT|CMN_RES_F2X2SUB_BIT|CMN_RES_F4X4_BIT|CMN_RES_PEN_M_BIT,
				NNS_G2D_VRAM_TYPE_2DMAIN );
///		PushSub_SetupPokeGraphic(ptr->SubDispCntPtr);

		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 2:
		{
			int i;
			CLACT_WORK_PTR act_ptr;
			PKTHLN_ACT_SETUP_PRM param = {
				ACT_MAX,4,{4,4,4,4}
			};
			ptr->ActCntPtr = PkthlnClAct_Init(ptr->HeapID, &param);

			//上下画面幅設定
			PkthlnClAct_SetDispDistance(ptr->ActCntPtr,
										0, 0,
										0, SUB_DISP_DISTANCE );
			//ポケモンアクター
			ptr->PokeActCntPtr = PokeAct_Init( ptr->HeapID, RUN_EVENT_POKE_NUM, PRI_POKE_MINE,
									  ptr->CmnResCntPtr, PkthlnClAct_GetClActSetAdr(ptr->ActCntPtr) );

			PkthlnClAct_SetResObjCode(ptr->ActCntPtr, 0, RES_CODE_RUN_SUB);
			PkthlnClAct_SetResObjCode(ptr->ActCntPtr, 1, RES_CODE_RUN_TRNS_POKE1);
			PkthlnClAct_SetResObjCode(ptr->ActCntPtr, 2, RES_CODE_RUN_TRNS_POKE2);
			PkthlnClAct_SetResObjCode(ptr->ActCntPtr, 3, RES_CODE_RUN_MAIN);
			//
///			PushSub_SetTrnsPokeRes(ptr->ActCntPtr, ptr->SubDispCntPtr);
			//サブ
			RunSub_SetObj( ptr->SubDispCntPtr, ptr->ActCntPtr );
			//メイン
			SetObj(ptr->ActCntPtr);
			//トランス
			PkthlnClAct_Trans(ptr->ActCntPtr);


			//カウントダウンアクター
			{
				CLACT_WORK_PTR	*act_adr;
				act_adr = PTFrame_SetCountDown( work, 0, ptr->CmnResCntPtr, ptr->ActCntPtr );
				//プライオリティセット
				CLACT_DrawPriorityChg( *act_adr, PRI_COUNT );
			}

			//メイン画面ＯＢＪ
			SetAct( ptr, ptr->ActCntPtr);

			RunSub_SetPokeAct( ptr->SubDispCntPtr, ptr->ActCntPtr, ptr->CmnResCntPtr );

			//サブ画面ポケモン
///			PushSub_SetPoke(ptr->ActCntPtr, ptr->SubDispCntPtr);
			//サブ画面ポケ以外のＯＢＪ
///			PushSub_SetObj(ptr->ActCntPtr, ptr->SubDispCntPtr);

			//
		}
		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 3:
		{
			int i;
			MONS_INFO info[RUN_EVENT_POKE_NUM];
			PCLACT_SET_PARAM param;
			ICON_INFO icon_info[RUN_EVENT_POKE_NUM];

			for(i=0;i<RUN_EVENT_POKE_NUM;i++){
				PTFrame_SetMonsInfo(work, i/ENTRY_MAX, i%ENTRY_MAX, &info[i]);

				param.ShadowPos[i] =
					PTFrame_GetPokeShdwPosType(PTFrame_GetPkthlnParam(work, i/ENTRY_MAX, i%ENTRY_MAX));

				//ポケモンアイコン情報取得
				icon_info[i].MonsNo = info[i].MonsNo;
				icon_info[i].Form = info[i].Form;
			}

			//ポケモンアイコン
			RunSub_SetupPokeIcon( ptr->SubDispCntPtr, icon_info );
			//ポケグラのセット
			{
				u8 net_id = PTFrameGetCurrentID(work);
				RunSub_SetupPokeGraphic(ptr->SubDispCntPtr, &info[net_id*ENTRY_MAX]);
			}
			//控えポケのグラフィックトランス
			RunSub_TransPokeGra( ptr->SubDispCntPtr, 0, 1);
			RunSub_TransPokeGra( ptr->SubDispCntPtr, 1, 2);

			param.Quick = 0;
			param.BGPriority = 2;
			param.Trans = 0;
			param.ResVramType = NNS_G2D_VRAM_TYPE_2DMAIN;
			param.DrawArea = NNS_G2D_VRAM_TYPE_2DMAIN;

			PokeAct_SetPokeActor(	ptr->PokeActCntPtr, RUN_EVENT_POKE_NUM,
									info, &param,
									PCLACT_TCB_PRIORITY,
									0 );

			//サブ画面ＯＢＪプライオリティセット
			RunSub_SetPriority( ptr->SubDispCntPtr, PTFrameGetCurrentID(work));

		}
		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 4:
		if ( PokeAct_CheckActSetTask(ptr->PokeActCntPtr) ){
			PEN_POS	pen_pos;
			EVT_HIT_DATA hit_data;
			int i;
			int my_net_id;

			my_net_id = PTFrameGetCurrentID(work);

			PTFrame_SetDefaultVBlankFunc(ptr->bgl);	// VBlankセット
			//描画を許可
			PTFrame_SetDraw(work, TRUE);

			ArchiveDataLoad(hit_data.Data, ARC_PKTHEVT_PARAM, NARC_pkthln_evt_info_run_hit_bin);
			//ポケセルアクター
			for (i=0;i<RUN_EVENT_POKE_NUM;i++){
				POKE_ACT_PTR poke_ptr = PokeAct_GetPokeActPtr(ptr->PokeActCntPtr, i);
				//各チームの最初のエントリーポケだけ表示
				if (i%ENTRY_MAX == 0){
					PokeAct_DispCnt(poke_ptr, 1);	//表示
				}

				//あたり判定データセット
				{
					HIT_TYPE hit_type;
					hit_type = PTFrame_GetPokeHitType(PTFrame_GetPkthlnParam(work, i/ENTRY_MAX, i%ENTRY_MAX));
					PokeAct_SetHitData(poke_ptr, hit_data.Data[hit_type-1].Ofs, hit_data.Data[hit_type-1].Range);
///					OS_Printf("hitdata::%d,%d\n",hit_data.Data[hit_type-1].Ofs,hit_data.Data[hit_type-1].Range);
				}

				//ポケモン初期位置
				{
					RUN_POKE *run_poke;
					POKE_ACT_PTR poke_ptr = PokeAct_GetPokeActPtr(ptr->PokeActCntPtr, i);

					run_poke = &ptr->Poke[i/ENTRY_MAX];
					run_poke->PokeActPtr[i%ENTRY_MAX] = poke_ptr;
///					push_poke->State = POKE_ALIVE;

					//テーブルで位置決定
					{
						int sx,sy;
						int range;
						//影の位置
						sx = START_POKE_POS_X;
						sy = START_POKE_POS_Y + START_POKE_POS_Y_OFS + (START_POKE_MARGINE * ((i/ENTRY_MAX)+1));

						run_poke->Dir = POKE_DIR_RIGHT;
						//向きセット
						PokeAct_SetDir(poke_ptr, POKE_DIR_RIGHT);
						//アクター位置セット
						PokeAct_SetPosShadow(poke_ptr, sx, sy);

						//タッチ半径セット
						range = PTFrame_GetPokeTouchRange();
						PokeAct_SetTouchRange(poke_ptr, range);

						run_poke->Pos.x = 0;
						run_poke->Pos.y = sy*FX32_ONE;

						//自分の先頭ポケのペン表示座標を保存
						if ( ((i/ENTRY_MAX)==my_net_id)&&((i%ENTRY_MAX)==0) ){
							int tx,ty;
							//タッチ中心座標取得
							PokeAct_GetTouchPosByShadowPos(poke_ptr, sx, sy, &tx, &ty);
							pen_pos.X = tx;
							pen_pos.Y = ty;
						}
					}//テーブルで位置決定
				} //ポケモン初期位置
			}	//end for

			//スタート地点でのポケのプライオリティセット
			for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
				RUN_POKE *run_poke;
				run_poke = &ptr->Poke[i];
				SetPokePriority(run_poke, run_poke->Pos.y/FX32_ONE, (i == PTFrameGetCurrentID(work)) );
			}

			{
				RUN_PARAM data;
				int i;
				RUN_POKE *run_poke;
				ArchiveDataLoad(&data, ARC_PKTHEVT_PARAM, NARC_pkthln_evt_info_run_bin);
#if 1
				{
					int m;
					for(m=0;m<5;m++){
						OS_Printf("run_prm:%d,%d,%d,%d,%d,%d,%d,%d\n",
								data.Power[m], data.Stamina[m], data.Accel1[m], data.Accel2[m], data.Panic[m],
								data.Speed[m], data.SpeedLow[m], data.SpeedMat[m]);
					}
				}
#endif
				//ゲーム時間セット
				ptr->CommTime = GAME_TIME;

				//時間表示
				RunSub_DispTime(ptr->SubDispCntPtr, ptr->CommTime);

				for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
					int j;
					//親の判定データ初期化
					ptr->HoldPoke[i] = FALSE;
					//パラメータ格納
					for(j=0;j<ENTRY_MAX;j++){
						run_poke = &ptr->Poke[i];
						SetPokeParam(work, &data, i, j, run_poke);
					}
					if (PTFrameGetCurrentID(work) == COMM_PARENT_ID){
						//AI用にポケモンデータをセットアップ
						RunAI_SetupPokeInfo( ptr->AICntPtr, i, run_poke );
					}
					//ネットＩＤ保存
					ptr->Poke[i].NetID = i;
				}
				//親のとき、初回送信データを作成
				if (PTFrameGetCurrentID(work) == COMM_PARENT_ID){
					COMM_EVENT_COMMON_DATA *data;
					data = PTFrame_GetEvtComCmnData(work);
					SetCommInfo(ptr,
							PKTHLN_CommPack_GetData(&data->SendShareData));
				}
			}

			//ペン表示
			PTFrame_SetPen( work, 0, ptr->CmnResCntPtr, ptr->ActCntPtr,
						    NNS_G2D_VRAM_TYPE_2DMAIN, 1,  &pen_pos);

			SetGraphic(ptr);
///			PushSub_WriteWinInfo(ptr->SubDispCntPtr);

			//ＯＢＪの表示
			GF_Disp_GX_VisibleControl( GX_PLANEMASK_OBJ, VISIBLE_ON );		// MAIN DISP OBJ ON
			GF_Disp_GXS_VisibleControl( GX_PLANEMASK_OBJ, VISIBLE_ON );		// SUB DISP OBJ ON

			//通信アイコン
			WirelessIconEasyPokethlon( NNS_G2D_VRAM_TYPE_2DMAIN );

			//次のシーケンスへ
			PTFrame_IncSubSeq(work);
		}
		break;


	case 5:
		//障害物データ作成
		if ( PTFrameGetCurrentID(work) == COMM_PARENT_ID ){
			int *data;
			data = &ptr->ParentObstData[0];
			//アーカイブからロード RUN_COURSE_NUM個からランダム
			{
				u8 crs_no = gf_rand()%RUN_COURSE_NUM;
				OS_Printf("マラソンコースナンバー：%d\n",crs_no);
				ArchiveDataLoad(data, ARC_PKTHEV_RUN_DAT, crs_no);
			}

			//AI用に障害物データをセットアップ
			RunAI_SetUpObstInfo(ptr->AICntPtr, data);
		}
		//次のシーケンスへ
		PTFrame_IncSubSeq(work);
		break;
	case 6:
		//初期化終了
		sys_PrintHeapFreeSize( ptr->HeapID );
		GF_ASSERT(sys_CheckHeapSafe( HEAPID_POKETHLON));
		return PTH_RC_END;
	}
	return PTH_RC_LOOP;
}
//--------------------------------------------------------------------------------------------
/**
 * 描画関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
BOOL PE_RUN_DrawFunc(PKTHLN_PTR work, void *pParam)
{
	PKTHLN_RUN_PTR ptr = PTFrame_GetEventWorkPtr(work);

	PkthlnClAct_Draw(ptr->ActCntPtr);
	return TRUE;
}

//--------------------------------------------------------------------------------------------
/**
 * 競技結果計算関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
BOOL PE_RUN_ResultFunc(PKTHLN_PTR work, void *pParam)
{
	int i,j;
	RSLT_PTR result_ptr;

	OS_Printf("競技結果データ作成\n");

	result_ptr = PTFrame_GetResultPtr(work);
	RSLT_Setup( result_ptr );

	for( i=0;i<ENTRY_MEMBER_NUM_MAX;i++ ){
		u16 rec;
		int round, len;
		rec = 0;

		rec = PTFrame_GetEvtResult(work, i);
		//メッセージのタグに合わせる
		round = rec / ROUND_LEN_INT;
		len = ((rec % ROUND_LEN_INT) * 10) / ROUND_LEN_INT;
		OS_Printf("レコード：%d,%d\n",round, len);
		RSLT_SetResult2( work, result_ptr, i, rec,
						round, len, 0, 1, 2, 1,
						msg_pkthln_rs_K7 );
	}

	//ソート
	RSLT_Sort(result_ptr, SORT_REC_LARGE);
	//得点セット
	PTC_CalcPoint(result_ptr, PKTHLN_EVT_RUN);

	//総得点に加算
	RSLT_AddTotalScore(result_ptr);

	//競技得点セット
	RSLT_SetEvtScore(result_ptr, PKTHLN_EVT_RUN);

	return TRUE;
}

//--------------------------------------------------------------------------------------------
/**
 * 終了関数
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*pParam		パラメータ
 *
 * @return	TRUE
 */
//--------------------------------------------------------------------------------------------
BOOL PE_RUN_EndFunc(PKTHLN_PTR work, void *pParam)
{
	int i;
	PKTHLN_RUN_PTR ptr = PTFrame_GetEventWorkPtr(work);

	// 通信アイコン撤去
	WirelessIconEasyEnd();

	//共有データクリア
	PTFrame_ClearEvtShareDataPtr(work);

	//スクリーンアーカイブ解放
///	sys_FreeMemoryEz(ptr->MainBgArc);
	//BG削除
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME0_M );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME1_M );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME2_M );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME3_M );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME0_S );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME1_S );
	GF_BGL_BGControlExit(ptr->bgl, GF_BGL_FRAME2_S );

	//BMP
	GF_BGL_BmpWinDel( &ptr->Win );

	//BGL解放
	sys_FreeMemoryEz(ptr->bgl);

	//アクター解放
	PkthlnClAct_Free(ptr->ActCntPtr);

	//ポケアクターコントローラ解放
	PokeAct_Free(ptr->PokeActCntPtr);
	//共通リソースコントローラ解放
	CmnRes_Free(ptr->CmnResCntPtr);

	//OAMレンダラー破棄
	REND_OAM_Delete();

	DeleteCharManager();
	DeletePlttManager();

	//AIコントローラー解放
	RunAI_End(ptr->AICntPtr);

	//サブ画面コントローラー解放
	RunSub_Free(ptr->SubDispCntPtr);

	//タッチフォントアンロード
	FontProc_UnloadFont(FONT_TOUCH);

	sys_VBlankFuncChange( NULL, NULL );	// VBlankセット
	sys_HBlankIntrSet( NULL,NULL );		// HBlankセット

	//イベントワーク解放
	PTFrame_FreeEventWork(work);

	// 上下画面を元に戻しておく
	sys.disp3DSW = DISP_3D_TO_MAIN;
	GF_Disp_DispSelect();

	//特殊効果オフ
	G2_BlendNone();
	//ヒープ解放
	sys_DeleteHeap( HEAPID_PT_RUN );

	return TRUE;
}

//--------------------------------------------------------------------------------------------
/**
 * VRAM設定		ポケスロンでは、ポケモン表示だけで0x30000必要となる。
 * VRAM_AB(0x40000)でないとはいらん
 *
 * @param	none
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetVramBank(void)
{
	GF_BGL_DISPVRAM tbl = {
		GX_VRAM_BG_64_E,				// メイン2DエンジンのBG
		GX_VRAM_BGEXTPLTT_NONE,			// メイン2DエンジンのBG拡張パレット

		GX_VRAM_SUB_BG_128_C,			// サブ2DエンジンのBG
		GX_VRAM_SUB_BGEXTPLTT_NONE,		// サブ2DエンジンのBG拡張パレット

		GX_VRAM_OBJ_256_AB,				// メイン2DエンジンのOBJ
		GX_VRAM_OBJEXTPLTT_NONE,		// メイン2DエンジンのOBJ拡張パレット

		GX_VRAM_SUB_OBJ_16_I,			// サブ2DエンジンのOBJ
		GX_VRAM_SUB_OBJEXTPLTT_NONE,	// サブ2DエンジンのOBJ拡張パレット

		GX_VRAM_TEX_NONE,				// テクスチャイメージスロット
		GX_VRAM_TEXPLTT_NONE			// テクスチャパレットスロット
	};
	GF_Disp_SetBank( &tbl );
}

//--------------------------------------------------------------------------------------------
/**
 * @brief	BG初期化
 * @param	*ini		BGL
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void BgInit(GF_BGL_INI * ini)
{
	{	/* BG SYSTEM */
  	  GF_BGL_SYS_HEADER BGsys_data = {
    	  GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BGMODE_0, GX_BG0_AS_2D,
    	};
  	  GF_BGL_InitBG( &BGsys_data );
  	}

  	//メイン
  	{	/* MAIN DISP BG0 */
    	GF_BGL_BGCNT_HEADER MBg0_Data = {
	      0, 0, 0x1000, 0,
    	  GF_BGL_SCRSIZ_512x256, GX_BG_COLORMODE_16,
		  GX_BG_SCRBASE_0xf000, GX_BG_CHARBASE_0x00000,
		  GX_BG_EXTPLTT_01, 3, 0, 0, FALSE
   	 };
   	 GF_BGL_BGControlSet( ini, GF_BGL_FRAME0_M, &MBg0_Data, GF_BGL_MODE_TEXT );
   	 GF_BGL_ScrClear( ini, GF_BGL_FRAME0_M );
 	}

	{	/* MAIN DISP BG1 */
  	  GF_BGL_BGCNT_HEADER MBg1_Data = {
    	  0, 0, 0x800, 0,
   	 	  GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
		  GX_BG_SCRBASE_0xd800, GX_BG_CHARBASE_0x00000,
		  GX_BG_EXTPLTT_01, 2, 0, 0, FALSE
   	 };
   	 GF_BGL_BGControlSet( ini, GF_BGL_FRAME1_M, &MBg1_Data, GF_BGL_MODE_TEXT );
   	 GF_BGL_ScrClear( ini, GF_BGL_FRAME1_M );
	}

	{	/* MAIN DISP BG2 */
  	  GF_BGL_BGCNT_HEADER MBg2_Data = {
    	  0, 0, 0x1000, 0,
   	 	  GF_BGL_SCRSIZ_512x256, GX_BG_COLORMODE_16,
		  GX_BG_SCRBASE_0xe000, GX_BG_CHARBASE_0x00000,
    	  GX_BG_EXTPLTT_01, 1, 0, 0, FALSE
   	 };
   	 GF_BGL_BGControlSet( ini, GF_BGL_FRAME2_M, &MBg2_Data, GF_BGL_MODE_TEXT );
   	 GF_BGL_ScrClear( ini, GF_BGL_FRAME2_M );
	}

	{	/* MAIN DISP BG3 */
    	GF_BGL_BGCNT_HEADER MBg3_Data = {
	      0, 0, 0x800, 0,
    	  GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
		  GX_BG_SCRBASE_0xd000, GX_BG_CHARBASE_0x04000,
		  GX_BG_EXTPLTT_01, 0, 0, 0, FALSE
   	 };
   	 GF_BGL_BGControlSet( ini, GF_BGL_FRAME3_M, &MBg3_Data, GF_BGL_MODE_TEXT );
   	 GF_BGL_ScrClear( ini, GF_BGL_FRAME3_M );
 	}

	  //サブ
	{	/* SUB DISP BG0 */
 	   GF_BGL_BGCNT_HEADER SBg0_Data = {
    	  	0, 0, 0x800, 0,
   	  		GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
			GX_BG_SCRBASE_0xf800, GX_BG_CHARBASE_0x0c000,
    		GX_BG_EXTPLTT_01, 0, 0, 0, FALSE
  	  };
 	  GF_BGL_BGControlSet( ini, GF_BGL_FRAME0_S, &SBg0_Data, GF_BGL_MODE_TEXT );
  	  GF_BGL_ScrClear( ini, GF_BGL_FRAME0_S );
 	}

 	{	/* SUB DISP BG1 */
	    GF_BGL_BGCNT_HEADER SBg1_Data = {
    	  	0, 0, 0x800, 0,
 	  		GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
 	   		GX_BG_SCRBASE_0xf000, GX_BG_CHARBASE_0x00000,
  	   		GX_BG_EXTPLTT_01, 2, 0, 0, FALSE
		};
    	GF_BGL_BGControlSet( ini, GF_BGL_FRAME1_S, &SBg1_Data, GF_BGL_MODE_TEXT );
    	GF_BGL_ScrClear( ini, GF_BGL_FRAME1_S );
	}

	{	/* SUB DISP BG2 */
		GF_BGL_BGCNT_HEADER SBg2_Data = {
			0, 0, 0x800, 0,
		    GF_BGL_SCRSIZ_256x256, GX_BG_COLORMODE_16,
      		GX_BG_SCRBASE_0xe000, GX_BG_CHARBASE_0x00000,
      		GX_BG_EXTPLTT_01, 3, 0, 0, FALSE
    	};
	    GF_BGL_BGControlSet( ini, GF_BGL_FRAME2_S, &SBg2_Data, GF_BGL_MODE_TEXT );
  	  	GF_BGL_ScrClear( ini, GF_BGL_FRAME2_S );
 	 }

	//レコードＢＧ非表示
	GF_Disp_GX_VisibleControl( GX_PLANEMASK_BG3, VISIBLE_OFF );
}

//--------------------------------------------------------------------------------------------
/**
 * @brief	グラフィックセット
 * @param	ptr			アプリポインタ
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetGraphic(PKTHLN_RUN_PTR ptr)
{
	//メインキャラ
	ArcUtil_BgCharSet(ARC_PKTHEV_RUN, NARC_pkthev_run_run_main_bg_ncgr,
						ptr->bgl, GF_BGL_FRAME0_M, 0, 0, FALSE, ptr->HeapID);
/**
	//土台スクリーン
	ptr->MainBgArc = ArcUtil_ScrnDataGet(ARC_PKTHEV_RUN, NARC_pkthev_run_run_main_bg_base_nscr,
						FALSE, &ptr->MainScrnData, ptr->HeapID);
	GF_BGL_ScreenBufSet( ptr->bgl, GF_BGL_FRAME0_M, ptr->MainScrnData->rawData, ptr->MainScrnData->szByte );
	GF_BGL_LoadScreen( ptr->bgl, GF_BGL_FRAME0_M, ptr->MainScrnData->rawData, ptr->MainScrnData->szByte, 0 );
*/
	ArcUtil_ScrnSet(ARC_PKTHEV_RUN, NARC_pkthev_run_run_main_bg_base_nscr,
						ptr->bgl, GF_BGL_FRAME0_M, 0, 0, FALSE, ptr->HeapID);
	//イン側スクリーン
	ArcUtil_ScrnSet(ARC_PKTHEV_RUN, NARC_pkthev_run_run_main_bg_inner_nscr,
						ptr->bgl, GF_BGL_FRAME1_M, 0, 0, FALSE, ptr->HeapID);
	//アウト側スクリーン
	ArcUtil_ScrnSet(ARC_PKTHEV_RUN, NARC_pkthev_run_run_main_bg_outer_nscr,
						ptr->bgl, GF_BGL_FRAME2_M, 0, 0, FALSE, ptr->HeapID);

	//メインパレット
	ArcUtil_PalSet( ARC_PKTHEV_RUN, NARC_pkthev_run_run_main_bg_nclr,
						PALTYPE_MAIN_BG, 0, 64, ptr->HeapID );
	//サブBG
	RunSub_SetBG(ptr->SubDispCntPtr);
}

//----------------------------------------------------------------------------
/**
 *	@brief		ＯＢＪセット
 *
 *	@param	pActCntPtr		アクターコントローラポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void SetObj(PKTHLN_CLACT_CNT_PTR pActCntPtr)
{
	PkthlnClAct_SetChar( pActCntPtr,
					ARC_PKTHEV_RUN, NARC_pkthev_run_run_main_obj_NCGR,
					RES_CODE_RUN_MAIN, NNS_G2D_VRAM_TYPE_2DMAIN);
	PkthlnClAct_SetPaltt( pActCntPtr,
					ARC_PKTHEV_RUN, NARC_pkthev_run_run_main_obj_NCLR,
					RES_CODE_RUN_MAIN, NNS_G2D_VRAM_TYPE_2DMAIN, RUN_MAIN_OBJ_PALETTE_NUM	);
	PkthlnClAct_SetCell( pActCntPtr,
					ARC_PKTHEV_RUN, NARC_pkthev_run_run_main_obj_NCER, RES_CODE_RUN_MAIN	);
	PkthlnClAct_SetAnm(	pActCntPtr,
					ARC_PKTHEV_RUN, NARC_pkthev_run_run_main_obj_NANR, RES_CODE_RUN_MAIN	);
}

//----------------------------------------------------------------------------
/**
 *	@brief		アクターセット
 *
 *  @param	ptr				競技ポインタ
 *	@param	pActCntPtr		アクターコントローラポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void SetAct( PKTHLN_RUN_PTR ptr, PKTHLN_CLACT_CNT_PTR pActCntPtr)
{
	int i;
	//障害物
	for (i=0;i<OBST_NUM_MAX;i++){
		PkthlnClAct_SetActor(pActCntPtr, 2, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_RUN_MAIN, ACT_CODE_RUN_OBST);
	}

	//ボールとか
	for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		PkthlnClAct_SetActor(pActCntPtr, 2, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_RUN_MAIN, ACT_CODE_RUN_BALL);
		PkthlnClAct_SetActor(pActCntPtr, 2, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_RUN_MAIN, ACT_CODE_RUN_STATE);
		PkthlnClAct_SetActor(pActCntPtr, 2, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_RUN_MAIN, ACT_CODE_RUN_BOOST);
		PkthlnClAct_SetActor(pActCntPtr, 2, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_RUN_MAIN, ACT_CODE_RUN_SMOG);
	}
	for(i=0;i<HIT_EFFECT_NUM;i++){
		PkthlnClAct_SetActor(pActCntPtr, 2, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_RUN_MAIN, ACT_CODE_RUN_HIT);
	}

	//交代ボタン
	PkthlnClAct_SetActor(pActCntPtr, 1, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_RUN_MAIN, ACT_CODE_RUN_CHANGE);
	//LAP
	PkthlnClAct_SetActor(pActCntPtr, 1, NNS_G2D_VRAM_TYPE_2DMAIN, RES_CODE_RUN_MAIN, ACT_CODE_RUN_LAP);


	//障害物
	for(i=0;i<OBST_NUM_MAX;i++){
		ptr->Obst[i].ActPtr = PkthlnClAct_GetActPtr(pActCntPtr, RES_CODE_RUN_MAIN, ACT_CODE_RUN_OBST);
	}

	//ボールとか
	for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		ptr->Poke[i].ChgBallActPtr = PkthlnClAct_GetActPtr(pActCntPtr, RES_CODE_RUN_MAIN, ACT_CODE_RUN_BALL);
		ptr->Poke[i].StateActPtr = PkthlnClAct_GetActPtr(pActCntPtr, RES_CODE_RUN_MAIN, ACT_CODE_RUN_STATE);
		ptr->Poke[i].BoostActPtr = PkthlnClAct_GetActPtr(pActCntPtr, RES_CODE_RUN_MAIN, ACT_CODE_RUN_BOOST);
		ptr->Poke[i].SmogActPtr = PkthlnClAct_GetActPtr(pActCntPtr, RES_CODE_RUN_MAIN, ACT_CODE_RUN_SMOG);

		PkthlnClAct_ChgAnm(ptr->Poke[i].ChgBallActPtr, 3);
		PkthlnClAct_ChgAnm(ptr->Poke[i].SmogActPtr, 8);
	}
	for(i=0;i<HIT_EFFECT_NUM;i++){
		ptr->HitActPtr[i] = PkthlnClAct_GetActPtr(pActCntPtr, RES_CODE_RUN_MAIN, ACT_CODE_RUN_HIT);
	}

	//交代ボタン
	ptr->ChgBtnActPtr = PkthlnClAct_GetActPtr(pActCntPtr, RES_CODE_RUN_MAIN, ACT_CODE_RUN_CHANGE);
	PkthlnClAct_ChgAnm(ptr->ChgBtnActPtr, 11);	//ボタンＯＦＦ状態
	PkthlnClAct_SetActive(ptr->ChgBtnActPtr, 1, 1);	//可視
	//位置決定
	{
		VecFx32 vec;
		vec.x = CHG_BTN_X*FX32_ONE;
		vec.y = CHG_BTN_Y*FX32_ONE;
		vec.z = 0;
		PkthlnClAct_SetPos(ptr->ChgBtnActPtr, &vec);
	}

	//LAP
	ptr->LapAct.LapActPtr = PkthlnClAct_GetActPtr(pActCntPtr, RES_CODE_RUN_MAIN, ACT_CODE_RUN_LAP);
	PkthlnClAct_ChgAnm(ptr->LapAct.LapActPtr, 10);
	ptr->LapAct.LapNum1Ptr = CmnRes_CreateF4X4Act(	ptr->CmnResCntPtr,
													PkthlnClAct_GetClActSetAdr(ptr->ActCntPtr),
													0, ptr->HeapID );
	ptr->LapAct.LapNum2Ptr = CmnRes_CreateF4X4Act(	ptr->CmnResCntPtr,
													PkthlnClAct_GetClActSetAdr(ptr->ActCntPtr),
													0, ptr->HeapID );
}



//----------------------------------------------------------------------------
/**
 *	@brief	シーケンス関数
 *
 *	@param	work		ポケスロンポインタ
 *	@param	*seq		シーケンサ
 *
 *	@return	FALSE
 */
//-----------------------------------------------------------------------------
static BOOL RUN_Func_Phase0(PKTHLN_PTR work, u8 *seq)
{
	int i;
	PKTHLN_RUN_PTR ptr = PTFrame_GetEventWorkPtr(work);

	switch(*seq){
	case 0:	//障害物データをローカルで作成
		for(i=0;i<OBST_NUM_MAX;i++){
			u8 type;
			u8 y;
			u16 x;
			type = ptr->ObstData[i] & 0xff;
			y = (ptr->ObstData[i] >> 8) & 0xff;
			x = (ptr->ObstData[i] >> 16) & 0xffff;
			OS_Printf("OBST:%d,%d,%d\n",type, x, y);
			if (type != 0){
				VecFx32 vec;
				ptr->Obst[i].Valid = TRUE;
				ptr->Obst[i].Type = type;
				ptr->Obst[i].X = x;
				ptr->Obst[i].Y = y;
				//アニメセット
				PkthlnClAct_ChgAnm(ptr->Obst[i].ActPtr, type-1);
				//可視状態
				PkthlnClAct_SetActive(ptr->Obst[i].ActPtr, 1, 1);
				//座標セット
				vec.z = 0;
				vec.x = (x+START_POKE_POS_X) * FX32_ONE;
				vec.y = (y+INNER_OFS) * FX32_ONE;
				PkthlnClAct_SetPos(ptr->Obst[i].ActPtr, &vec);
				//プライオリティ
				SetObstPriority(&ptr->Obst[i]);
			}
		}

		//障害物配置
		CalcObstDispPos(ptr, 0);

		(*seq)++;
		//通信同期待ちセット
		PTFrame_SetSynchroID(work, PKTLN_SYNC_ID_RUN_START_WAIT);
		break;
	case 1:
		//みんな一緒にフェードインリクエスト
		WIPE_SYS_Start(	WIPE_PATTERN_FSAM, WIPE_TYPE_SHUTTERIN_DOWN,
						WIPE_TYPE_SHUTTERIN_DOWN, WIPE_FADE_BLACK,
						WIPE_DEF_DIV, WIPE_DEF_SYNC, ptr->HeapID );
		(*seq)++;
		break;
	case 2:
		//フェードイン待ち
		if( WIPE_SYS_EndCheck() ){
			//シーケンスシフト
			PTFrame_SetNextFuncTblIdx(work, RUN_SEQ_PHASE1);
		}
	}

	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	シーケンス関数
 *
 *	@param	work		ポケスロンポインタ
 *	@param	*seq		シーケンサ
 *
 *	@return	FALSE
 */
//-----------------------------------------------------------------------------
static BOOL RUN_Func_Phase1(PKTHLN_PTR work, u8 *seq)
{
	BOOL rc;
	PKTHLN_RUN_PTR ptr = PTFrame_GetEventWorkPtr(work);

	switch(*seq){
	case 0:	//カウント
		if ( PTFrame_CountDown(work) ){
			(*seq)++;
		}
		break;
	case 1:
		CommMain(work);
		if ( ControlMain(work) ){
			(*seq)++;
		}
		break;
	case 2:
		CommMain(work);
		if ( PTFrame_DispEnd(work) ){
			//フェードアウトリクエスト
			WIPE_SYS_Start(	WIPE_PATTERN_WMS, WIPE_TYPE_FADEOUT,
							WIPE_TYPE_FADEOUT, WIPE_FADE_BLACK,
							WIPE_DEF_DIV, WIPE_DEF_SYNC, ptr->HeapID );
			//シーケンスシフト
			PTFrame_SetNextFuncTblIdx(work, RUN_SEQ_PHASE2);
		}
		break;
	}


	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	シーケンス関数
 *
 *	@param	work		ポケスロンポインタ
 *	@param	*seq		シーケンサ
 *
 *	@return	TRUE
 */
//-----------------------------------------------------------------------------
static BOOL RUN_Func_Phase2(PKTHLN_PTR work, u8 *seq)
{
	int i,j;
	PKTHLN_RUN_PTR ptr = PTFrame_GetEventWorkPtr(work);

	if (*seq == 0){
		//フェードアウト待ち
		if ( WIPE_SYS_EndCheck() ){
			*seq = 1;
		}
		return FALSE;
	}

	//結果はすべて親が管理しているので、子は処理をスルー
	if (PTFrameGetCurrentID(work) != COMM_PARENT_ID){
		return TRUE;
	}

	//結果セット
	for (i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		u16 len;
		RUN_POKE *run_poke;
		run_poke = &ptr->Poke[i];
		len = (run_poke->Round*ROUND_LEN_INT) + run_poke->Pos.x/FX32_ONE;
		PTFrame_SetEvtResultOrg(work, i, len);
	}
	return TRUE;
}

//--------------------------------------------------------------------------------------------
/**
 * @brief	通信データ関連メイン処理
 * @param	work		ポケスロンアプリポインタ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void CommMain(PKTHLN_PTR work)
{
	int i,j;
	PKTHLN_RUN_PTR ptr;
	RUN_CHILD_DATA *child_data;
	RUN_PARENT_DATA *parent;
	COMM_EVENT_COMMON_DATA *data;
	data = PTFrame_GetEvtComCmnData(work);
	ptr = PTFrame_GetEventWorkPtr(work);

	//親動作
	if (PTFrameGetCurrentID(work) == COMM_PARENT_ID){

		//終了フラグが立っているならば、通信データのセットのみを行い処理を打ち切る
		if (ptr->EndFlg){
			//情報セット
			SetCommInfo(ptr,  PKTHLN_CommPack_GetData(&data->SendShareData));
			return;
		}

		//親データは直接レシーバにセット
		{
			RUN_CHILD_DATA *child;
			RUN_CHILD_DATA *child_rec;

			child_rec = PKTHLN_CommPack_GetData(&data->ReciveData[0]);
			child = PKTHLN_CommPack_GetData(&data->SendData);
			(*child_rec) = (*child);
		}
		//時間経過
#ifdef PM_DEBUG					//こっちデバッグ用
		if (!DebugPkthlnWk.TimeInfinity){
			if (ptr->CommTime > 0){
				ptr->CommTime--;
			}
		}
#else							//こっち製品用
		if (ptr->CommTime > 0){
			ptr->CommTime--;
		}
#endif

		parent = PKTHLN_CommPack_GetData(&data->SendShareData);
		//プレーヤー数ループ
		for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
			RUN_CHILD_DATA *child_data;
			child_data = PKTHLN_CommPack_GetData(&data->ReciveData[i]);
			//タッチ状況を整理
			if (child_data->TouchValid){
				if ( (ptr->TpState[i].Trg)&&(ptr->TpState[i].Cont) ){
					ptr->TpState[i].Trg = FALSE;
				}else if((!ptr->TpState[i].Trg)&&(!ptr->TpState[i].Cont)){
					ptr->TpState[i].Trg = TRUE;
					ptr->TpState[i].Cont = TRUE;
				}
			}else{
				ptr->TpState[i].Trg = FALSE;
				ptr->TpState[i].Cont = FALSE;
			}

			//交代ボタンのグラフィックを決定する
			SetBtnState(ptr, i, CheckChgBtnTouch(ptr, child_data->TpX, child_data->TpY));

			if (ptr->Poke[i].ChgFlg){	//交代中
				//子機からの反応を取得
				if ( (ptr->Poke[i].ChgState == CHG_BALL_UP)&&(child_data->ChgState == CHILD_CHG_UP_END) ){
					OS_Printf("%dのボール打ち上げが終了\n");
					//ポケ交代
					ptr->Poke[i].RunPokeIdx = (ptr->Poke[i].RunPokeIdx+1)%ENTRY_MAX;
					//ボール落下アニメに移行する
					ptr->Poke[i].ChgState = CHG_BALL_DOWN;
					OS_Printf("%dの次のポケはインデックス%d\n",i, ptr->Poke[i].RunPokeIdx);
				}else if( (ptr->Poke[i].ChgState == CHG_BALL_DOWN)&&(child_data->ChgState == CHILD_CHG_DOWN_END) ){
					OS_Printf("%dのボール落下が終了\n");
					//ポケ交代終了
					ptr->Poke[i].ChgState = CHG_BALL_NONE;
					ptr->Poke[i].ChgFlg = 0;
					//パニックモード回復
					ptr->Poke[i].PanicMode = 0;
				}
				//交代中はタッチしていないとみなす
				ptr->HoldPoke[i] = FALSE;
				ptr->Poke[i].TouchTime = 0;
				ptr->Poke[i].TPos.x = 0;
				ptr->Poke[i].TPos.y = 0;
				ptr->Poke[i].TPos.z = 0;
				ptr->Poke[i].LastTPos = ptr->Poke[i].TPos;
			}else if (ptr->Poke[i].Param[ ptr->Poke[i].RunPokeIdx ].FatState ==
																		POKE_ST_PANIC){	//気絶中
				//気絶中はタッチしていないとみなす
				ptr->HoldPoke[i] = FALSE;
				ptr->Poke[i].TouchTime = 0;
				ptr->Poke[i].TPos.x = 0;
				ptr->Poke[i].TPos.y = 0;
				ptr->Poke[i].TPos.z = 0;
				ptr->Poke[i].LastTPos = ptr->Poke[i].TPos;
			}else if (ptr->Poke[i].HitFrame){			//ヒットポーズ中
				//ヒットポーズ中はタッチしていないとみなす
				ptr->HoldPoke[i] = FALSE;
				ptr->Poke[i].TouchTime = 0;
				ptr->Poke[i].TPos.x = 0;
				ptr->Poke[i].TPos.y = 0;
				ptr->Poke[i].TPos.z = 0;
				ptr->Poke[i].LastTPos = ptr->Poke[i].TPos;
			}else{
				BOOL clear_flg = FALSE;
				if (ptr->TpState[i].Trg){
					//交代ボタンをタッチしたか？
					if ( CheckChgBtnTouch(ptr, child_data->TpX, child_data->TpY) ){
						//交代
						ptr->Poke[i].ChgFlg = 1;
						ptr->Poke[i].ChgState = CHG_BALL_UP;
						//アクションポイント加算「交代」
						PTFrame_AddActionPoint(	work, ptr->Poke[i].NetID, ptr->Poke[i].RunPokeIdx, ADD_TYPE_CHANGE, 1 );
					}else{
						BOOL rc;
						//自分のポケモンをタッチしたかを検出
						rc = CheckPokeTouch(ptr, i, child_data->TpX, child_data->TpY);
						//自分のポケか？
						if ( rc ){
							//ホールド登録
							ptr->HoldPoke[i] = TRUE;
							//タッチ座標記憶
							ptr->Poke[i].TPos.x = child_data->TpX * FX32_ONE;
							ptr->Poke[i].TPos.y = child_data->TpY * FX32_ONE;
							ptr->Poke[i].TPos.z = 0;
							ptr->Poke[i].LastTPos = ptr->Poke[i].TPos;
						}
					}
				}else if (ptr->TpState[i].Cont){	//ベタ押し
					//タッチ時間加算
					if (ptr->Poke[i].TouchTime < TOUCH_TIME_MAX){
						ptr->Poke[i].TouchTime++;
					}else{
						//ブレーキ状態
						ptr->Brake = 1;
					}
					//ホールドポケいなければ、処理しない
					if (ptr->HoldPoke[i] == FALSE){
						continue;
					}
					//ベタタッチ座標更新
					ptr->Poke[i].LastTPos.x = child_data->TpX * FX32_ONE;
					ptr->Poke[i].LastTPos.y = child_data->TpY * FX32_ONE;
				}else{	//タッチしていない
					if ( ptr->HoldPoke[i] != FALSE ){
						//加速度算出時間内ならば、リリースポイントから加速度を求める
						if (ptr->Poke[i].TouchTime <= TOUCH_TIME_ACCEL){
							//移動ベクトル決定処理を行う
							ptr->Poke[i].MoveVecDcd = TRUE;
						}
						//ホールド解除
						ptr->HoldPoke[i] = FALSE;
						//ブレーキ状態解除
						ptr->Brake = 0;
					}
					clear_flg = TRUE;
				}
				//移動ベクトル決定処理
				if (ptr->Poke[i].MoveVecDcd){
					u8 idx;
					VecFx32 poke_speed;
					VecFx32 vec;
					VecFx32 add = {0,0,0};
					float len, sp_len;
					fx32 scalar;
					float accel,speed;
					float max_speed;

					idx = ptr->Poke[i].RunPokeIdx;

					accel = ptr->Poke[i].Param[idx].Accel1;			//テクニック依存
					speed = ptr->Poke[i].Param[idx].Accel2;			//スピード依存
					max_speed = GetMaxSpeed( &ptr->Poke[i], idx );
					scalar = (accel*speed/ACCEL_DIV)*FX32_ONE;
					VEC_Subtract( &ptr->Poke[i].LastTPos, &ptr->Poke[i].TPos, &vec );
///					OS_Printf("VEC_XY=%d,%d\n",vec.x , vec.y);
					if (vec.x < 0){
						if ( vec.x < -(BACK_STRK*FX32_ONE) ){
							OS_Printf("マイナス方向の移動はさせない\n");
							//追加仕様　マイナスストロークで交代
							ptr->Poke[i].ChgFlg = 1;
							ptr->Poke[i].ChgState = CHG_BALL_UP;
							//アクションポイント加算「交代」
							PTFrame_AddActionPoint(	work, ptr->Poke[i].NetID, ptr->Poke[i].RunPokeIdx, ADD_TYPE_CHANGE, 1 );

						}
						vec.x = 0;
						vec.y = 0;
						vec.z = 0;
					}
					VEC_MultAdd( scalar, &vec, &add, &vec );
					OS_Printf("accel_len_bf=%d\n",VEC_Mag(&vec));
					len = VEC_Mag(&vec) / FX32_ONE;
					//求めた長さに加速係数・スピード係数を乗算し、補正係数で除算する
					OS_Printf("accel_len_af=%f\n",len);

					poke_speed = ptr->Poke[i].Speed;

					//仮加算(ここでの仮は一時的というもので、デバッグの意味合いは含んでいません)
					AddSpeedVec(&poke_speed, &vec, &poke_speed);
					//限界スピードを超えたかをチェック
					sp_len = VEC_Mag(&poke_speed);
					if ( sp_len > max_speed*FX32_ONE ){		//超えた
						VecFx32 add = {0,0,0};
						//正規化後max_speed倍
						VEC_Normalize(&poke_speed, &poke_speed);
						VEC_MultAdd(max_speed*FX32_ONE, &poke_speed, &add, &ptr->Poke[i].Speed);
						OS_Printf("補正\n");
					}else{		//超えてない
						//求めた加速度をスピードに加算
						AddSpeedVec(&ptr->Poke[i].Speed, &vec, &ptr->Poke[i].Speed);
						OS_Printf("そのまま\n");
					}

					//アクションポイント加算「ダッシュ回数」 <<ストロークの結果ダッシュスピードを超えていたら加算
					{
						fx32 sp_len;
						RUN_POKE *run_poke;
						run_poke = &ptr->Poke[i];
						sp_len = VEC_Mag(&run_poke->Speed);
						if ( sp_len >= (run_poke->Param[run_poke->RunPokeIdx].SpeedMax-3)*FX32_ONE ){
							PTFrame_AddActionPoint(	work, run_poke->NetID, run_poke->RunPokeIdx, ADD_TYPE_DASH, 1 );
						}
					}

					ptr->Poke[i].MoveVecDcd = FALSE;
				}

				if (clear_flg){
					ptr->Poke[i].TouchTime = 0;
					ptr->Poke[i].TPos.x = 0;
					ptr->Poke[i].TPos.y = 0;
					ptr->Poke[i].TPos.z = 0;
					ptr->Poke[i].LastTPos = ptr->Poke[i].TPos;
				}
			}//end if (ptr->Poke[i].ChgFlg)

		}	//end for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++)

		//AI実行
#ifdef PM_DEBUG										//こっちデバッグ用
		if ( !DebugPkthlnWk.AI_Stop ){
			RunAI_Execute(work, ptr->AICntPtr, ptr->CommTime);
		}
#else												//こっち製品用
		RunAI_Execute(work, ptr->AICntPtr, ptr->CommTime);
#endif

		//ポケモンの移動
		MovePoke(work);

		//終了判定
///		OS_Printf("ＧａｍｅＴｉｍｅ= %d\n",ptr->CommTime);
		if (ptr->CommTime <= 0){
			ptr->EndFlg = 1;		//終了フラグ
		}else{
			ptr->EndFlg = 0;
		}

		//情報セット
		SetCommInfo(ptr,  PKTHLN_CommPack_GetData(&data->SendShareData));
	}
}

//--------------------------------------------------------------------------------------------
/**
 * @brief	通信データセット
 * @param	ptr		ポケスロンアプリポインタ
 * @param	parent	親データ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetCommInfo(PKTHLN_RUN_PTR ptr, RUN_PARENT_DATA *parent)
{
	int i,j;
	u8 chg_state;
	int st3;
	int fat_state;
	u8 minus;

	chg_state = 0;
	st3 = 0;
	fat_state = 0;
	minus = 0;
	for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		int x,y;
		int dir;
		u8 st1,st2;
		RUN_POKE *run_poke;
		run_poke = &ptr->Poke[i];

		st1 = 0;
		st1 += run_poke->RunPokeIdx;
		st1 += run_poke->MoveMode << 2;

		chg_state += ( run_poke->ChgState << (i*2) );
		st2 = (run_poke->ChgFlg << 7) + run_poke->Round;
		parent->PokeY[i] = run_poke->Pos.y / FX32_ONE;
		parent->PokeLen[i] = run_poke->Pos.x / FX32_ONE;
		parent->St1[i] = st1;
		parent->St2[i] = st2;
		for(j=0;j<ENTRY_MAX;j++){
			//スタミナ残量から
			fat_state += run_poke->Param[j].FatState << ( (i*ENTRY_MAX+j)*2 );
		}
		//ボタンステート
		parent->BtnSt[i] = ptr->BtnSt[i];
		//マイナス周回フラグ
		minus += (run_poke->RoundMinusFlg<<i);
	}
	parent->ChgState = chg_state;
	parent->St3 = fat_state;
	parent->St3 += (ptr->EndFlg << 24);
	parent->St3 += (ptr->HitEff << 25);
	parent->St3 += (minus << 26);
	parent->HitPosX = ptr->HitEffX;
	parent->HitPosY = ptr->HitEffY;
	parent->Time = ptr->CommTime;
}

//----------------------------------------------------------------------------
/**
 *	@brief		メイン関数
 *
 *	@param	work	ポケスロンポインタ
 *
 *	@return	終了でTRUE
 */
//-----------------------------------------------------------------------------
static BOOL ControlMain(PKTHLN_PTR work)
{
	PKTHLN_RUN_PTR ptr = PTFrame_GetEventWorkPtr(work);

	RUN_CHILD_DATA *child_data;
	COMM_EVENT_COMMON_DATA *data;
	data = PTFrame_GetEvtComCmnData(work);
	child_data = PKTHLN_CommPack_GetData(&data->SendData);
	child_data->TouchValid = FALSE;

	//終了検出
	{
		u8 end;
		RUN_PARENT_DATA *parent;
		parent = PKTHLN_CommPack_GetData(&data->ReciveShareData);
		end = (parent->St3 >> 24) & 0x1;	//1ビットマスク


#ifdef PM_DEBUG
		if (sys.trg & PAD_BUTTON_X){
			end = 1;
		}
#endif
		if (end){
			//「FINISH」とかぶらないようにラップ表示を消す
			PkthlnClAct_SetActive(ptr->LapAct.LapActPtr, 1, 0);
			CLACT_SetDrawFlag(ptr->LapAct.LapNum1Ptr, 0);
			CLACT_SetDrawFlag(ptr->LapAct.LapNum2Ptr, 0);

			//アクター停止
			PkthlnClAct_AllAnmStop(ptr->ActCntPtr, 1);
			PokeAct_AllAnmStop(ptr->PokeActCntPtr, 1);

			//レコードコールバック関数をセット
			PTFrame_SetRecordCallBack(work, RecCallBack);
#if 0
			//ニューレコード用にレコードをセット
			{
				u8 my_net_id;
				u8 round;
				u16 len;
				my_net_id = PTFrameGetCurrentID(work);
				round = parent->St2[my_net_id] & 0x7f;		//7ビットマスク
				len = parent->PokeLen[my_net_id];
				//フレームワークにニューレコードチェック用のレコード値をセット
				PTFrame_SetCheckRecord(work, len);
				SetRecordStr(ptr, round, len);
			}
#endif
			//アクションポイント加算「得点回数」	<<各ポケの走行距離/ROUND_LEN_INTで周回数を求めその値を得点回数とする
			if ( PTFrameGetCurrentID(work) == COMM_PARENT_ID ){
				u8 i,j;
				for (i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
					for(j=0;j<ENTRY_MAX;j++){
						u8 round;
						RUN_POKE *poke = &ptr->Poke[i];
						fx32 len = poke->Len[j];
						round = (len/ROUND_LEN_INT) / FX32_ONE;
						PTFrame_AddActionPoint(	work, i, j, ADD_TYPE_GET, round );
					}
				}
			}

			return TRUE;
		}
	}

	//タッチ座標検出
	if (GF_TP_GetTrg()){
		//アクションポイント加算「タッチ回数」
		PTFrame_AddActionPoint(	work, PTFrameGetCurrentID(work), ENTRY_MAX, ADD_TYPE_TOUCH, 1 );
	}
	if (GF_TP_GetCont()){
		//通信データに座標をセット
		child_data->TpX = sys.tp_x;
		child_data->TpY = sys.tp_y;
		child_data->TouchValid = TRUE;
	}

	SetDraw(work);

	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief		描画座標関連セット関数
 *
 *	@param	work	ポケスロンポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void SetDraw(PKTHLN_PTR work)
{
	int i;
	u8 my_net_id;
	COMM_EVENT_COMMON_DATA * data;
	RUN_PARENT_DATA *parent;

	PKTHLN_RUN_PTR ptr = PTFrame_GetEventWorkPtr(work);

	data = PTFrame_GetEvtComCmnData(work);
	parent = PKTHLN_CommPack_GetData(&data->ReciveShareData);
	my_net_id = PTFrameGetCurrentID(work);

/**
	ptr->Len++;
	if (ptr->Len>=1024){
		ptr->Len = 0;
		OS_Printf("一周\n");
	}
*/
	for (i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		RunSub_SetIconPos(ptr->SubDispCntPtr, i, parent->PokeLen[i]);
	}
	GF_BGL_ScrollReq( ptr->bgl, GF_BGL_FRAME0_M, GF_BGL_SCROLL_X_SET, parent->PokeLen[my_net_id] );
	GF_BGL_ScrollReq( ptr->bgl, GF_BGL_FRAME1_M, GF_BGL_SCROLL_X_SET, parent->PokeLen[my_net_id]/2 );
	GF_BGL_ScrollReq( ptr->bgl, GF_BGL_FRAME2_M, GF_BGL_SCROLL_X_SET, parent->PokeLen[my_net_id]*2 );

	CalcPokeDispPos(work, my_net_id, ptr->Poke, data);
	CalcObstDispPos(ptr,  parent->PokeLen[my_net_id]);

	//週回数フィル
	{
		u8 round;
		u16 len;
		u8 minus;
		round = parent->St2[my_net_id] & 0x7f;		//7ビットマスク
		minus = (parent->St3 >> 26 ) & 0xf;	//4ビットマスク
		minus = (minus >> my_net_id) & 0x1;	//1ビットマスク
		if (minus){
			len = 0;
		}else{
			len = parent->PokeLen[my_net_id];
		}
		RunSub_FillRound(ptr->SubDispCntPtr, round, len);
		//ラウンド更新表示
		{
			u8 end;
			RUN_POKE *run_poke;
			run_poke = &ptr->Poke[my_net_id];

			end = (parent->St3 >> 24) & 0x1;	//1ビットマスク
			if(!end){
				//ラップ表示
				DispLap(&ptr->LapAct, round);
			}
		}
	}

	//タイマー
	RunSub_DispTime(ptr->SubDispCntPtr, parent->Time);

	//ボタン状態
	switch(parent->BtnSt[my_net_id]){
	case BTN_ST_PUSH_OK:
		ptr->PushSE = 0;
		PkthlnClAct_ChgAnmCheck(ptr->ChgBtnActPtr, 11);
		break;
	case BTN_ST_PUSH_NG:
		ptr->PushSE = 0;
		PkthlnClAct_ChgAnmCheck(ptr->ChgBtnActPtr, 13);
		break;
	case BTN_ST_PUSH_OK_PUSH:
		//初検出でＳＥ
		if (ptr->PushSE == 0){
			ptr->PushSE = 1;
			Snd_SePlay( SE_THLON_CHANGE_OK );
		}
		PkthlnClAct_ChgAnmCheck(ptr->ChgBtnActPtr, 12);
		break;
	case BTN_ST_PUSH_NG_PUSH:
		//初検出でＳＥ
		if (ptr->PushSE == 0){
			ptr->PushSE = 1;
			Snd_SePlay( SE_THLON_CHANGE_NG );
		}
		PkthlnClAct_ChgAnmCheck(ptr->ChgBtnActPtr, 14);
		break;
	case BTN_ST_PUSH_OK_FLASH:
		ptr->PushSE = 0;
		PkthlnClAct_ChgAnmCheck(ptr->ChgBtnActPtr, 15);
		break;
	}

	//ゴールラインフィル
	FillGoalLine(ptr->bgl, parent->PokeLen[my_net_id]);

	//ラスト３秒
	PTFrame_DispLastCount(work, parent->Time);
}

//----------------------------------------------------------------------------
/**
 *	@brief	ポケモンをタッチしているかを判定する
 *
 *	@param	ptr		競技ポインタ
 *	@param	inNetID	ネットID
 *	@param	inX		X座標
 *	@param	inY		Y座標
 *
 *	@return u8 タッチしたポケモンインデックス
 */
//-----------------------------------------------------------------------------
static BOOL CheckPokeTouch(PKTHLN_RUN_PTR ptr, const u8 inNetID, const u16 inX, const u16 inY)
{
	u8 i;

	RUN_POKE *run_poke;
	POKE_ACT_PTR poke_ptr;
	int tx,ty;

	run_poke = &ptr->Poke[inNetID];

	if (0/*run_poke->State == POKE_NONE*/){
		return FALSE;
	}

	GF_ASSERT(run_poke->RunPokeIdx < ENTRY_MAX);

	poke_ptr = run_poke->PokeActPtr[run_poke->RunPokeIdx];

	//タッチ中心座標取得
	PokeAct_GetTouchPosByShadowPos(poke_ptr, START_POKE_POS_X, run_poke->Pos.y/FX32_ONE, &tx, &ty);

	if ( PokeAct_CheckTouch(poke_ptr, tx*FX32_ONE, ty*FX32_ONE, inX, inY) ){
		//タッチしている
		OS_Printf("%d:ポケにタッチ\n",inNetID);
		return TRUE;
	}
	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	交代ボタンをタッチしているかを判定する
 *
 *	@param	ptr		競技ポインタ
 *	@param	inX		X座標
 *	@param	inY		Y座標
 *
 *	@return u8 タッチしたポケモンインデックス
 */
//-----------------------------------------------------------------------------
static BOOL CheckChgBtnTouch(PKTHLN_RUN_PTR ptr, const u16 inX, const u16 inY)
{
	if ( (0<=inX)&&(inX<CHG_BTN_W) &&
		 (0<=inY)&&(inY<CHG_BTN_H)	){
		return TRUE;
	}
	return FALSE;
}

//----------------------------------------------------------------------------
/**
 *	@brief	ポケモン移動
 *
 *	@param	work		ポケスロンワークポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void MovePoke(PKTHLN_PTR work)
{
	HIT_RC hit_rc, mat_rc;
	u16 rc;
	int i,j;
	BOOL hit_eff;
	VecFx32 hit_vec;
	u8 hit_frame_flg[ENTRY_MEMBER_NUM_MAX];

	PKTHLN_RUN_PTR ptr = PTFrame_GetEventWorkPtr(work);

	ptr->HitEff = 0;

	//ヒットポーズ中の処理
	for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		hit_frame_flg[i] = 0;
		if (ptr->Poke[i].HitFrame){
			MovePokeHitFrame(work, ptr, &ptr->Poke[i]);
			hit_frame_flg[i] = 1;
			continue;
		}
	}

	for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		VecFx32 old_pos;
		RUN_POKE *run_poke;

		//ヒット中は移動関連処理をスルー
		if (hit_frame_flg[i]){
			continue;
		}

		run_poke = &ptr->Poke[i];

		//今の座標を保存
		old_pos = run_poke->Pos;
		//座標更新
		VEC_Add(&run_poke->Pos, &run_poke->Speed, &run_poke->Pos);
		//走行距離加算
		run_poke->Len[run_poke->RunPokeIdx] += run_poke->Speed.x;

/**
		//デバッグ
		{
			fx32 len;
			fx32 max_sp;
			//限界スピードを超えたかをチェック
			len = VEC_Mag(&run_poke->Speed);
			max_sp = run_poke->Param[run_poke->RunPokeIdx].SpeedMax*FX32_ONE;
			if (len > max_sp){
				OS_Printf("%d,%d:最大速度オーバー\n",len,max_sp);
				GF_ASSERT(0);
			}
		}
*/
		//Y方向リミット計算
		if (run_poke->Pos.y < START_POKE_POS_Y * FX32_ONE){
			run_poke->Pos.y = START_POKE_POS_Y * FX32_ONE;
		}else if(Y_LIMIT * FX32_ONE < run_poke->Pos.y){
			run_poke->Pos.y = Y_LIMIT * FX32_ONE;
		}

		//障害物とのヒット
		rc = HitCheckObst(ptr, run_poke->HitRc,
				PokeAct_GetHitRange(run_poke->PokeActPtr[run_poke->RunPokeIdx]),
				&old_pos, &run_poke->Pos, &run_poke->Pos);
		mat_rc = (rc >> 8) & 0xff; //8ビットマスク
		hit_rc = rc & 0xff;		//8ビットマスク

		if (mat_rc == HIT_RC_MAT){
			run_poke->MatOn = 1;
		}else{
			run_poke->MatOn = 0;
		}
		run_poke->HitRc = hit_rc;

		switch(hit_rc){
		case HIT_RC_UWALL:
			if (run_poke->Speed.y > 0){
				run_poke->Speed.y *= (-1);
			}
			break;
		case HIT_RC_RWALL:
			if (run_poke->Speed.x < 0){
				run_poke->Speed.x *= (-1);
			}
			break;
		case HIT_RC_DWALL:
			if (run_poke->Speed.y < 0){
				run_poke->Speed.y *= (-1);
			}
			break;
		case HIT_RC_LWALL:
			if (run_poke->Speed.x > 0){
				run_poke->Speed.x *= (-1);
			}
			break;
		case HIT_RC_LU_VRT:
			if (run_poke->Speed.x > 0){
				run_poke->Speed.x *= (-1);
			}
			if (run_poke->Speed.y > 0){
				run_poke->Speed.y *= (-1);
			}
			break;
		case HIT_RC_RU_VRT:
			if (run_poke->Speed.x < 0){
				run_poke->Speed.x *= (-1);
			}
			if (run_poke->Speed.y > 0){
				run_poke->Speed.y *= (-1);
			}
			break;
		case HIT_RC_RD_VRT:
			if (run_poke->Speed.x < 0){
				run_poke->Speed.x *= (-1);
			}
			if (run_poke->Speed.y < 0){
				run_poke->Speed.y *= (-1);
			}
			break;
		case HIT_RC_LD_VRT:
			if (run_poke->Speed.x > 0){
				run_poke->Speed.x *= (-1);
			}
			if (run_poke->Speed.y < 0){
				run_poke->Speed.y *= (-1);
			}
			break;
		}

		//ポケモンとのヒット
		hit_eff = HitCheckPoke(work, ptr->Poke, &hit_vec);

		if ((!ptr->HitEff)&&hit_eff){
			ptr->HitEff = 1;
			ptr->HitEffX = hit_vec.x / FX32_ONE;
			ptr->HitEffY = hit_vec.y / FX32_ONE;
		}

		//１周刻みでＸの位置をループさせる
		if (run_poke->Pos.x >= ROUND_LEN*FX32_ONE){
			run_poke->Pos.x = run_poke->Pos.x - (ROUND_LEN*FX32_ONE);
			//周回数インクリメント(マイナス状態からのゴールライン通過の場合はインクリメントしない)
			if ((!run_poke->RoundMinusFlg)&&(run_poke->Round < ROUND_MAX)){
					run_poke->Round++;
			}
			//最大周回数セット
			if ( (run_poke->MaxRound < run_poke->Round) ){
				run_poke->MaxRound = run_poke->Round;
			}
			run_poke->RoundMinusFlg = 0;	//マイナス周フラグオフ
		}else if (run_poke->Pos.x < 0 ){		//逆戻りがあった場合
			run_poke->Pos.x = (ROUND_LEN*FX32_ONE) + run_poke->Pos.x;
			//周回数デクリメント
			if (run_poke->Round > 0){
				run_poke->Round--;
			}else if (run_poke->Round == 0){
				run_poke->RoundMinusFlg = 1;	//マイナス周フラグオン
			}
		}

		//減速処理
		{
			fx32 scalar;
			float weight;
			VecFx32 vec;
			fx32 len, sp_len;

			vec = run_poke->Speed;
			len = VEC_Mag(&vec);

			//交代中ではなく、砂利の上にいるときの処理
			if ( (!run_poke->ChgFlg)&&(run_poke->MatOn )){
				fx32 mat_scalar;
				mat_scalar = run_poke->Param[run_poke->RunPokeIdx].SpeedMatMax * FX32_ONE;
				if (len > mat_scalar){
					VecFx32 add = {0,0,0};
					VecFx32 mat_vec;
					mat_vec = run_poke->Speed;
					VEC_Normalize(&mat_vec, &mat_vec);
					//速度制限
					VEC_MultAdd( mat_scalar, &mat_vec, &add, &mat_vec );
					run_poke->Speed = mat_vec;

					//設定しなおし
					vec = run_poke->Speed;
					len = VEC_Mag(&vec);
				}
			}

			if (len > 0){
///				OS_Printf("SP_VEC_XY=%d,%d\n",run_poke->Speed.x , run_poke->Speed.y);
				weight = 1.0;			//固定
				scalar = (weight * DECEL_COEF) * FX32_ONE;
				//ブレーキ分
				if (ptr->Brake){
					scalar += (3*FX32_ONE);
				}
				VEC_Normalize(&vec, &vec);
				vec.x = FX_Mul(vec.x, scalar);
				vec.y = FX_Mul(vec.y, scalar);
				len = VEC_Mag(&vec);
				sp_len = VEC_Mag(&run_poke->Speed);
				if (sp_len>=len){
					VEC_Subtract( &run_poke->Speed, &vec, &run_poke->Speed);
				}else{
					run_poke->Speed.x = 0;
					run_poke->Speed.y = 0;
					OS_Printf("速度が0に戻った\n");
				}
#ifdef PM_DEBUG
				if (i==0){
					if (sp_len!=0){
						fx32 d_len;
						d_len = VEC_Mag(&run_poke->Speed) / FX32_ONE;
						OS_Printf("d_len=%f\n",d_len);
					}
				}
#endif
			}
		}

		//マッハ状態の検出
		{
			fx32 sp_len;
			sp_len = VEC_Mag(&run_poke->Speed);
			if( sp_len  >=
					(run_poke->Param[run_poke->RunPokeIdx].SpeedMax-1)*FX32_ONE ){
				run_poke->MoveMode = MOVE_MACH;		//マッハ状態
			}else if ( sp_len >= (run_poke->Param[run_poke->RunPokeIdx].SpeedMax-3)*FX32_ONE ){
				run_poke->MoveMode = MOVE_DASH;		//走り状態
			}else if (sp_len == 0){
				run_poke->MoveMode = MOVE_STOP;		//停止状態
			}else{
				run_poke->MoveMode = MOVE_NORMAL;	//通常状態
			}
		}
		//スタミナの増減
		if (!run_poke->ChgFlg){		//交代中ではない？
			for(j=0;j<ENTRY_MAX;j++){
				float stamina = run_poke->Param[j].Stamina;
				if (j == run_poke->RunPokeIdx){	//現在走っている？
					if (run_poke->Param[j].FatState != POKE_ST_PANIC){	//気絶していない

						//走ってる
						switch(run_poke->MoveMode){
						case MOVE_STOP:
							stamina+=STAMINA_INC;
							break;
						case MOVE_NORMAL:
						case MOVE_DASH:
						case MOVE_MACH:
							stamina-=STAMINA_DEC;
							break;
						}
						//回復（気絶復帰モードで分岐）
						if (run_poke->PanicMode){
							if (stamina > FATIGUE_START ){
								stamina = FATIGUE_START;
							}
						}else{
							if (stamina > run_poke->Param[j].StaminaMax ){
								stamina = run_poke->Param[j].StaminaMax;
							}
						}
					}else if (run_poke->Param[j].FatState == POKE_ST_PANIC){	//気絶
						//気絶カウンタ
						OS_Printf("気絶回復中\n");
						OS_Printf("気絶値%d\n",run_poke->PanicCount);
						run_poke->PanicCount--;
						if (run_poke->PanicCount == 0){
							//疲労状態で復帰
							run_poke->Param[j].FatState = POKE_ST_FATIGUE;
							stamina = FATIGUE_START;
						}
					}
				}else{
					//待機中
					stamina += STAMINA_INC;
					if (stamina > run_poke->Param[j].StaminaMax){
						stamina = run_poke->Param[j].StaminaMax;
					}
				}

#ifdef DEBUG_STAMINA_INF
				if (i==0){
					stamina = run_poke->Param[j].StaminaMax;
				}
#endif

				if (stamina <= 0){
					GF_ASSERT(j == run_poke->RunPokeIdx);		//気絶は走ってるポケだけ
					run_poke->Param[j].Stamina = 0;
					if (run_poke->Param[j].FatState != POKE_ST_PANIC){
						//気絶状態
						run_poke->Param[j].FatState = POKE_ST_PANIC;
						//気絶モードにする（交代しないと治らない）
						run_poke->PanicMode = 1;
						//気絶カウンタセット
						run_poke->PanicCount = run_poke->Param[j].PanicTime;
						OS_Printf("気絶値をセット%d_%d\n",run_poke->PanicCount,run_poke->Param[j].PanicTime);
						//アクションポイント加算「失敗回数」
						PTFrame_AddActionPoint(	work, run_poke->NetID, run_poke->RunPokeIdx, ADD_TYPE_FAIL, 1 );
					}
				}else if (stamina <= FATIGUE_START){
					run_poke->Param[j].Stamina = stamina;
					//疲労状態
					run_poke->Param[j].FatState = POKE_ST_FATIGUE;
				}else{
					run_poke->Param[j].Stamina = stamina;
					//通常状態
					run_poke->Param[j].FatState = POKE_ST_NORMAL;
				}
			}
		}
	}	//end for
}

//----------------------------------------------------------------------------
/**
 *	@brief	当たり判定中のポーズフレームのカウント
 *
 *  @param	work			ポケスロンワークポインタ
 *  @param	ptr				競技ポインタ
 *	@param	run_poke		競技ポケモンワークポインタ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void MovePokeHitFrame(PKTHLN_PTR work, PKTHLN_RUN_PTR ptr, RUN_POKE *run_poke)
{
#if 0
	BOOL hit_eff;
	VecFx32 hit_vec;

	//ポケモンとのヒット
	hit_eff = HitCheckPoke(work, ptr->Poke, &hit_vec);

	if ((!ptr->HitEff)&&hit_eff){
		ptr->HitEff = 1;
		ptr->HitEffX = hit_vec.x / FX32_ONE;
		ptr->HitEffY = hit_vec.y / FX32_ONE;
	}
#endif
	//ヒットポーズカウンタデクリメント
	if (run_poke->HitFrame>0){
		run_poke->HitFrame--;
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	自分のポケの表示位置から相対的に考えて、相手のポケの位置を算出
 *
 *  @param	work			ポケスロンワークポインタ
 *  @param	inMyNetID		自分のネットID
 *  @param	inPokeList		競技ポケモンリストポインタ
 *	@param	commData		通信データ
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void CalcPokeDispPos(PKTHLN_PTR work,
							const u8 inMyNetID,
							RUN_POKE *inPokeList,
							COMM_EVENT_COMMON_DATA *commData)
{
	int i,j;
	int my_len,len;
	int disp_x;
	PKTHLN_RUN_PTR ptr;
	BOOL is_parent;

	RUN_PARENT_DATA *parent;
	RUN_CHILD_DATA *child_data;

	parent = PKTHLN_CommPack_GetData(&commData->ReciveShareData);

	ptr = PTFrame_GetEventWorkPtr(work);

	//自分のポケのＸ座標を取得
	my_len = parent->PokeLen[inMyNetID];
	//ヒットエフェクト表示
	{
		u8 hit_eff;
		VecFx32 hit_vec = {0,0,0};
		hit_eff = (parent->St3 >> 25) & 0x1;		//1ビットマスク
		if (hit_eff){
			len = my_len - parent->HitPosX;
			//画面表示位置を算出
			if (len >= ROUND_LEN-256){		//差分が1周-1画面分ある場合は自分よりも前に描画する必要がある
				disp_x = START_POKE_POS_X + (ROUND_LEN-len);
			}else{
				disp_x = START_POKE_POS_X - len;
			}
			//座標セット
			hit_vec.x = disp_x * FX32_ONE;
			hit_vec.y = parent->HitPosY * FX32_ONE;

			PkthlnClAct_SetPos(ptr->HitActPtr[ptr->HitEffIdx], &hit_vec);	//ヒットエフェクト

			//アニメ
			PkthlnClAct_SetActive(ptr->HitActPtr[ptr->HitEffIdx], 1, 1);
			PkthlnClAct_ChgAnm(ptr->HitActPtr[ptr->HitEffIdx], 9);

			//インデックス変更
			ptr->HitEffIdx = (ptr->HitEffIdx+1)%HIT_EFFECT_NUM;

			//画面内ならヒットＳＥ
			if ( (0<=disp_x)&&(disp_x<256) ){
				Snd_SePlayEx( SE_RUN_HIT_POKE, SE_PLAYER_HIT  );
			}
		}
	}

	//親判定
	if (inMyNetID == COMM_PARENT_ID){
		is_parent = TRUE;
	}else{
		is_parent = FALSE;
	}

	for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		VecFx32 vec;
		POKE_ACT_PTR poke_ptr;
		BOOL npc;
		u8 run_poke_idx;
		u8 chg;
		u8 idx;
		u8 boost;
		int state;

		BOOL mine;

		if (inMyNetID == i){
			mine = TRUE;
		}else{
			mine = FALSE;
		}

		run_poke_idx = parent->St1[i] & 0x3;	//2ビットマスク
		//相対距離を算出
		len = parent->PokeLen[i] - my_len;

		if (my_len > ROUND_LEN-300){		//ゴールラインが前方に見えるとき（余裕を見て300ドット）
			//ゴールライン前方300ドット以内にいるポケは、描画位置を補正
			if (parent->PokeLen[i] < 300){
				len = (ROUND_LEN-my_len)+parent->PokeLen[i];
			}
		}else if(my_len < 100){		//ゴールラインが後方に見えるとき（余裕を見て100ドット）
			//ゴールライン後方100ドット以内にいるポケは、描画位置を補正
			if (parent->PokeLen[i] > ROUND_LEN-100){
				len = -((ROUND_LEN-parent->PokeLen[i])+my_len);
			}
		}
		disp_x = START_POKE_POS_X + len;

		idx = (i*ENTRY_MAX) + run_poke_idx;
		chg = (parent->St2[i] >> 7) & 0x1;		//1ビットマスク
		state = parent->St3;
		state = (state >>(2*idx) ) & 0x3;			//2ビットマスク
		boost = (parent->St1[i] >> 2 ) & 0x3;		//2ビットマスク

		poke_ptr = inPokeList[i].PokeActPtr[run_poke_idx];

		vec.x = disp_x * FX32_ONE;
		vec.y = parent->PokeY[i] * FX32_ONE;
		vec.z = 0;

		//NPC判定
		if ( PTFrame_GetPlayerNum(work) <= i ){
			npc = TRUE;
			child_data = PKTHLN_CommPack_GetData(&commData->ReciveData[i]);
		}else{
			npc = FALSE;
			child_data = PKTHLN_CommPack_GetData(&commData->SendData);
		}

		if (inMyNetID == i){	//デモ要求が自分自身
			ChangeDemo(ptr->SubDispCntPtr, &inPokeList[i], &vec, parent,
				i, run_poke_idx, child_data,is_parent, TRUE, FALSE);	//<<ＮＰＣなわけがない。FALSE固定
		}else{					//デモ要求が他者
			ChangeDemo(ptr->SubDispCntPtr, &inPokeList[i], &vec, parent,
				i, run_poke_idx, child_data,is_parent, FALSE, npc);
		}

		//サブ画面アイコン描画
		RunSub_SetDrawSubDispIcon(ptr->SubDispCntPtr, i, run_poke_idx, chg, state);

		//表示範囲内かを判断
		if((!inPokeList[i].DemoVanish)&&(DISP_X_MIN <= disp_x)&&(disp_x <= DISP_X_MAX)){		//表示
			PokeAct_DispCnt(poke_ptr, TRUE);
		}else{		//非表示
			PokeAct_DispCnt(poke_ptr, FALSE);
		}

		for(j=0;j<ENTRY_MAX;j++){
			POKE_ACT_PTR my_poke_ptr;
			my_poke_ptr = inPokeList[i].PokeActPtr[j];
			//座標セット
			PokeAct_SetPosShadow(my_poke_ptr, disp_x, parent->PokeY[i]);	//ポケ
		}
		//プライオリティセット
		SetPokePriority(&inPokeList[i], parent->PokeY[i], (i == PTFrameGetCurrentID(work)) );

		{
			VecFx32 bst_vec;
			const PKTHPOKE_PARAM *param;
			param = PTFrame_GetPkthlnParam(work, i, run_poke_idx);

			SetStateActPos(	param, &vec, inPokeList[i].StateActPtr );	//ステート

			//ブースト位置はすべて同じ位置
			bst_vec = vec;
			bst_vec.y -= BOOST_OFS;
			PkthlnClAct_SetPos(inPokeList[i].BoostActPtr, &bst_vec);	//ブースト
		}


		if ( !chg ){		//交代中ではない
			u8 boost_flg = 0;
			u8 panic_flg = 0;
			//ブースト表示
			switch(boost){
			case MOVE_DASH:
				if (inPokeList[i].MoveModeLocal != boost){
					PkthlnClAct_SetActive(inPokeList[i].BoostActPtr, 1, 1);
					PkthlnClAct_ChgAnm(inPokeList[i].BoostActPtr, 4);
				}
				//ポケのアニメ変更
				PokeAct_SetAnm(poke_ptr, ANM_TYPE_DASH);
				boost_flg = 1;

				//ダッシュ状態に移行したらSE鳴らす
				if ( (inPokeList[i].BoostTemp == MOVE_STOP)||(inPokeList[i].BoostTemp == MOVE_NORMAL) ){
					if (!inPokeList[i].BoostSeFlg){
						PlaySeDispCheck(disp_x, SE_RUN_DASH_EFF, mine);
						inPokeList[i].BoostTemp = MOVE_DASH;
						inPokeList[i].BoostSeFlg = 1;
					}
				}
				break;
			case MOVE_MACH:
				if (inPokeList[i].MoveModeLocal != boost){
					PkthlnClAct_SetActive(inPokeList[i].BoostActPtr, 1, 1);
					PkthlnClAct_ChgAnm(inPokeList[i].BoostActPtr, 5);
				}
				//ポケのアニメ変更
				PokeAct_SetAnm(poke_ptr, ANM_TYPE_DASH);
				boost_flg = 1;

				//ダッシュ状態に移行したらSE鳴らす
				if ( (inPokeList[i].BoostTemp == MOVE_STOP)||(inPokeList[i].BoostTemp == MOVE_NORMAL) ){
					if (!inPokeList[i].BoostSeFlg){
						PlaySeDispCheck(disp_x, SE_RUN_DASH_EFF, mine);
						inPokeList[i].BoostTemp = MOVE_MACH;
						inPokeList[i].BoostSeFlg = 1;
					}
				}
				break;
			default:
				PkthlnClAct_SetActive(inPokeList[i].BoostActPtr, 1, 0);
				inPokeList[i].BoostTemp = boost;
				inPokeList[i].BoostSeFlg = 0;
			}

			//ステート表示
			switch(state){
			case POKE_ST_FATIGUE:
				PkthlnClAct_SetActive(inPokeList[i].StateActPtr, 1, 1);
				PkthlnClAct_ChgAnmCheck(inPokeList[i].StateActPtr, 6);
				break;
			case POKE_ST_PANIC:
				if (inPokeList[i].FatStateLocal != state){
					PkthlnClAct_SetActive(inPokeList[i].StateActPtr, 1, 1);
					PkthlnClAct_ChgAnm(inPokeList[i].StateActPtr, 7);
				}
				//ポケのアニメ変更
				PokeAct_SetAnm(poke_ptr, ANM_TYPE_PANIC_MORE);
				panic_flg = 1;

				//気絶ＳＥ ずっとコールさせる
				if (mine){
					//"自分のPLAYER"でSE再生終了したかチェック
					if( Snd_SePlayCheckByPlayerNo(SE_PLAYER_MINE) == FALSE ){
						PlaySeDispCheck(disp_x, SE_THLON_RUNNING_OUT, mine);
					}
				}else{
					//"自分以外のPLAYER"でSE再生終了したかチェック
					if( Snd_SePlayCheckByPlayerNo(SE_PLAYER_OTHERS) == FALSE ){
						PlaySeDispCheck(disp_x, SE_THLON_RUNNING_OUT, mine);
					}
				}

				break;
			default:
				PkthlnClAct_SetActive(inPokeList[i].StateActPtr, 1, 0);
			}

			//ダッシュ状態でも気絶異常でもないときは、歩行アニメ
			if ((!boost_flg)&&(!panic_flg)){
				PokeAct_SetAnm(poke_ptr, ANM_TYPE_WALK);
			}
		}else{		//交代中
			PkthlnClAct_SetActive(inPokeList[i].BoostActPtr, 1, 0);
			PkthlnClAct_SetActive(inPokeList[i].StateActPtr, 1, 0);
		}

		inPokeList[i].MoveModeLocal = boost;
		inPokeList[i].FatStateLocal = state;
	}	//end for

	//上画面控えポケの汗状態表示
	{
		u8 run_poke_idx;
		int state, st1,st2;
		u8 idx1,idx2;
		u8 n1,n2;
#if 0
		run_poke_idx = parent->St1[inMyNetID] & 0x3;	//2ビットマスク
		next1 = (run_poke_idx+1)%ENTRY_MAX;
		next2 = (next1+1)%ENTRY_MAX;

		idx1 = (inMyNetID*ENTRY_MAX) + next1;
		idx2 = (inMyNetID*ENTRY_MAX) + next2;
		state = parent->St3;
		st1 = (state >>(2*idx1) ) & 0x3;			//2ビットマスク
		st2 = (state >>(2*idx2) ) & 0x3;			//2ビットマスク
		RunSub_SetDrawSweat(ptr->SubDispCntPtr, st1, st2);
#endif
		n1 = RunSub_GetEntryIdx( ptr->SubDispCntPtr, 0);
		n2 = RunSub_GetEntryIdx( ptr->SubDispCntPtr, 1);

		idx1 = (inMyNetID*ENTRY_MAX) + n1;
		idx2 = (inMyNetID*ENTRY_MAX) + n2;
		state = parent->St3;
		st1 = (state >>(2*idx1) ) & 0x3;			//2ビットマスク
		st2 = (state >>(2*idx2) ) & 0x3;			//2ビットマスク
		RunSub_SetDrawSweat(ptr->SubDispCntPtr, st1, st2);
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	自分のポケの表示位置から相対的に考えて、障害物の配置を行う
 *
 *  @param	ptr				競技ポインタ
 *  @param	inMyLen			走行距離
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void CalcObstDispPos(PKTHLN_RUN_PTR ptr, const int inMyLen)
{
	u8 i;
	int my_len;
	//描画範囲を算出
	//自分のポケのＸ座標を取得
	my_len = inMyLen;

	//全障害物の座標を見て描画するかを決める
	for(i=0;i<OBST_NUM_MAX;i++){
		//障害物データ取得
		if (ptr->Obst[i].Valid){
			VecFx32 vec;
			u16 x,y;
			int disp_x;
			int len;
			//相対距離を算出
			x = ptr->Obst[i].X;
			y = ptr->Obst[i].Y;
			len = my_len - x;
			//画面表示位置を算出
			if (len >= ROUND_LEN-256){
				//周回距離（0〜1023）が自分の方が多く、差分が1周-1画面分ある場合は自分よりも前に描画する必要がある
				disp_x = START_POKE_POS_X + (ROUND_LEN-len);
			}else if(len <= -(ROUND_LEN-256)){
				//周回距離（0〜1023）が相手の方が多く、差分が1周-1画面分ある場合は自分よりも後ろに描画する必要がある
				disp_x = START_POKE_POS_X - (ROUND_LEN+len);
			}else{
				disp_x = START_POKE_POS_X - len;
			}
			//座標セット
			vec.z = 0;
			vec.x = disp_x*FX32_ONE;
			vec.y = (y+INNER_OFS)*FX32_ONE;
			PkthlnClAct_SetPos(ptr->Obst[i].ActPtr, &vec);
			//表示範囲内かを判断
			if((DISP_X_MIN <= disp_x)&&(disp_x <= DISP_X_MAX)){		//表示
				PkthlnClAct_SetActive(ptr->Obst[i].ActPtr, 1, 1);
			}else{		//非表示
				PkthlnClAct_SetActive(ptr->Obst[i].ActPtr, 1, 0);
			}
		}else{
			break;
		}
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	ボール上昇アニメ
 *
 *  @param	sub_ptr			サブ画面コントローラポインタ
 *  @param	run_poke		競技ポケモン
 *  @param	inTPos			タッチ位置
 *  @param	inNetID			ネットID
 *  @param	inRunPokeIdx	走行ポケモンインデックス
 *  @param	outChildData	子通信データ
 *  @param	inReqNpcMv		リクエストはNPCか？
 *  @param	inReqSubDemo	上画面切り替えデモ行うか？
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void BallUpAnm(	RUN_SUB_CNT_PTR sub_ptr, RUN_POKE *run_poke, const VecFx32 *inTPos,
						const u8 inNetID, const u8 inRunPokeIdx, RUN_CHILD_DATA *outChildData,
						const BOOL inReqNpcMv, const BOOL inReqSubDemo)
{
	switch(run_poke->ChgSeq){
	case 0:
		{
			int x;
			PkthlnClAct_SetPos(run_poke->ChgBallActPtr, inTPos);
			//煙アニメ開始
			PkthlnClAct_SetPos(run_poke->SmogActPtr, inTPos);
			PkthlnClAct_SetActive(run_poke->SmogActPtr, 1, 1);	//可視
			PkthlnClAct_ChgAnm(run_poke->SmogActPtr, 8);
			//ボール出現
			PkthlnClAct_SetActive(run_poke->ChgBallActPtr, 1, 1);
			//ポケ隠す
			PokeAct_DispCnt(run_poke->PokeActPtr[inRunPokeIdx], 0);
			run_poke->DemoVanish = TRUE;
			//カウンタ初期化
			run_poke->BallMvCount = 0;

			//画面内なら打ち上げＳＥ
			x = inTPos->x / FX32_ONE;
			PlaySeDispCheck(x, SE_RUN_CHANGE_OUT1, inReqSubDemo);
		}
		//シーケンスチェンジ
		run_poke->ChgSeq++;
		break;
	case 1:
		{
			VecFx32 vec;
			//ボール座標変更
			vec = *PkthlnClAct_GetPos(run_poke->ChgBallActPtr);
			vec.y -= BALL_MOVE_SPEED;
			vec.x = inTPos->x;			//ボールはポケの位置
			PkthlnClAct_SetPos(run_poke->ChgBallActPtr, &vec);
			PkthlnClAct_SetPos(run_poke->SmogActPtr, inTPos);
			run_poke->BallMvCount++;
			if (run_poke->BallMvCount >= BALL_MOVE_COUNT){	//目標到達？
				//シーケンスチェンジ
				run_poke->ChgSeq++;
			}
		}
		break;
	case 2:
		//自分のポケならば、上画面の表示変更デモ
		if (inReqSubDemo){
			if (RunSub_PokeChangeMain(sub_ptr, inRunPokeIdx)){
				//ボール落下を親に通達
				outChildData->ChgState = CHILD_CHG_UP_END;
				run_poke->ChgSeq++;
			}
		}else{
			if (inReqNpcMv){	//ＮＰＣ動作要求
				//ダミースライド関数
				if (RunSub_NpcPokeChangeMain(sub_ptr, inNetID)){
					//ボール落下を親に通達
					outChildData->ChgState = CHILD_CHG_UP_END;
					run_poke->ChgSeq++;
				}
			}else{
				run_poke->ChgSeq++;
			}
		}
		break;
	case 3:
		//待機
		break;
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	ボール降下アニメ
 *
 *  @param	run_poke		競技ポケモン
 *  @param	inTPos			タッチ位置
 *  @param	inNetID			ネットID
 *  @param	inRunPokeIdx	走行ポケモンインデックス
 *  @param	outChildData	子通信データ
 *  @param	inReqSend		親機に終了を送信する必要があるか？
 *  @param	inReqSubDemo	上画面切り替えデモ行うか？
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void BallDownAnm(RUN_POKE *run_poke, const VecFx32 *inTPos,
						const u8 inNetID, const u8 inRunPokeIdx, RUN_CHILD_DATA *outChildData,
						const BOOL inReqSend, const BOOL inReqSubDemo)
{
	switch(run_poke->ChgSeq){
	case 0:
		{
			int x;
			VecFx32 vec;
			//ボールの位置を画面上にセット
			vec = *inTPos;
			vec.y -= (BALL_MOVE_SPEED*BALL_MOVE_COUNT);
			PkthlnClAct_SetPos(run_poke->ChgBallActPtr, &vec);
			//ボール出現
			PkthlnClAct_SetActive(run_poke->ChgBallActPtr, 1, 1);
			//ポケ隠す
			PokeAct_DispCnt(run_poke->PokeActPtr[inRunPokeIdx], 0);
			//カウンタ初期化
			run_poke->BallMvCount = 0;

			//画面内なら下りＳＥ
			x = inTPos->x / FX32_ONE;
			PlaySeDispCheck(x, SE_RUN_CHANGE_IN1, inReqSubDemo);
		}
		//シーケンスチェンジ
		run_poke->ChgSeq++;
		break;
	case 1:
		{
			VecFx32 vec;
			//ボール座標変更
			vec = *PkthlnClAct_GetPos(run_poke->ChgBallActPtr);
			vec.y += BALL_MOVE_SPEED;
			vec.x = inTPos->x;			//ボールはポケの位置
			PkthlnClAct_SetPos(run_poke->ChgBallActPtr, &vec);
			run_poke->BallMvCount++;
			if (run_poke->BallMvCount >= BALL_MOVE_COUNT){	//目標到達？
				//煙位置セット
				PkthlnClAct_SetPos(run_poke->SmogActPtr, inTPos);
				//シーケンスチェンジ
				run_poke->ChgSeq++;
			}
		}
		break;
	case 2:
		if (inReqSend){
			//ボール落下終了を親に通達
			outChildData->ChgState = CHILD_CHG_DOWN_END;
		}
		//ボールと煙はポケの位置
		PkthlnClAct_SetPos(run_poke->ChgBallActPtr, inTPos);
		PkthlnClAct_SetPos(run_poke->SmogActPtr, inTPos);
		//シーケンスチェンジ
		run_poke->ChgSeq++;
	case 3:
		//ボールと煙はポケの位置
		PkthlnClAct_SetPos(run_poke->ChgBallActPtr, inTPos);
		PkthlnClAct_SetPos(run_poke->SmogActPtr, inTPos);
		//待機
		break;
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	交代変更終了アニメ
 *
 *  @param	run_poke		競技ポケモン
 *  @param	inNetID			ネットID
 *  @param	inRunPokeIdx	走行ポケモンインデックス
 *  @param	outChildData	子通信データ
 *  @param	inReqSend		親機に終了を送信する必要があるか？
 *  @param	inReqSubDemo	上画面切り替えデモ行うか？
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void ChangeEndAnm(	RUN_POKE *run_poke,
							const u8 inNetID, const u8 inRunPokeIdx, RUN_CHILD_DATA *outChildData,
							const BOOL inReqSend, const BOOL inReqSubDemo	)
{
	//ポケ出現
	PokeAct_DispCnt(run_poke->PokeActPtr[inRunPokeIdx], 1);
	run_poke->DemoVanish = FALSE;
	//煙りだす
	PkthlnClAct_SetActive(run_poke->SmogActPtr, 1, 1);	//可視
	PkthlnClAct_ChgAnm(run_poke->SmogActPtr, 8);
	//ボールバニッシュ
	PkthlnClAct_SetActive(run_poke->ChgBallActPtr, 1, 0);
	if (inReqSend){
		//ステートを初期化
		outChildData->ChgState = CHILD_CHG_NONE;
	}

	{
		VecFx32 vec;
		int x;
		//煙座標変更
		vec = *PkthlnClAct_GetPos(run_poke->SmogActPtr);
		x = vec.x / FX32_ONE;
		PlaySeDispCheck(x, SE_RUN_CHANGE_IN2, inReqSubDemo);		//煙発生時ＳＥ
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	交代デモ
 *
 *  @param	sub_ptr			サブ画面コントローラポインタ
 *  @param	run_poke		競技ポケモン
 *  @param	inShwPos		影の位置
 *  @param	inParent		親通信データ
 *  @param	inNetID			ネットID
 *  @param	inRunPokeIdx	走行ポケモンインデックス
 *  @param	outChildData	子通信データ
 *  @param	inIsParent		親か？
 *  @param	inReqSubDemo	上画面切り替えデモ行うか？
 *  @param	inIsNPC			NPCか？
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void ChangeDemo(	RUN_SUB_CNT_PTR sub_ptr,	RUN_POKE *run_poke, const VecFx32 *inSdwPos,
						const RUN_PARENT_DATA *inParent, const u8 inNetID,
						const u8 inRunPokeIdx, RUN_CHILD_DATA *outChildData,
						const BOOL inIsParent, const BOOL inReqSubDemo, const BOOL inIsNPC)
{
	VecFx32 t_vec;
	int tx,ty;
	u8 chg_st;
	u8 flg;		//初検出フラグ
	flg = 0;

	chg_st = ( inParent->ChgState >> (inNetID*2) ) & 0x3;	//2ビットマスク
	//ステート検出
	if (run_poke->ChgStateLocal != chg_st){	//ローカルステート差異がある場合
		//ステート更新
		run_poke->ChgStateLocal = chg_st;
		//シーケンサ初期化
		run_poke->ChgSeq = 0;
		//初検出フラグ
		flg = 1;
	}

	//タッチ中心座標検出
	PokeAct_GetTouchPosByShadowPos(run_poke->PokeActPtr[inRunPokeIdx],
									inSdwPos->x/FX32_ONE, inSdwPos->y/FX32_ONE, &tx, &ty);
	t_vec.x = tx * FX32_ONE;
	t_vec.y = ty * FX32_ONE;
	t_vec.z = 0;

	switch(run_poke->ChgStateLocal){
	case CHG_BALL_UP:		//ボール上昇
		{
			BOOL npc_mv;
			if (inIsParent&&inIsNPC){	//自分が親で、デモ要求がＮＰＣ
				npc_mv = TRUE;
			}else{
				npc_mv = FALSE;
			}
			BallUpAnm(	sub_ptr, run_poke, &t_vec,
						inNetID, inRunPokeIdx, outChildData,
						npc_mv, inReqSubDemo	);
		}
		break;
	case CHG_BALL_DOWN:		//ボール降下
		{
			BOOL req_send;
			BOOL npc_mv;
			if (inIsParent&&inIsNPC){	//自分が親で、デモ要求がＮＰＣ
				npc_mv = TRUE;
			}else{
				npc_mv = FALSE;
			}

			//ＮＰＣ動作要求かサブ画面デモ要求があった場合は、親に終了を送る必要がある
			req_send = npc_mv | inReqSubDemo;
			BallDownAnm(run_poke, &t_vec, inNetID, inRunPokeIdx, outChildData, req_send, inReqSubDemo);
		}
		break;
	case CHG_BALL_NONE:
		//初検出ならば実行
		if (flg){
			BOOL req_send;
			BOOL npc_mv;
			if (inIsParent&&inIsNPC){	//自分が親で、デモ要求がＮＰＣ
				npc_mv = TRUE;
			}else{
				npc_mv = FALSE;
			}
			//ＮＰＣ動作要求かサブ画面デモ要求があった場合は、親に終了を送る必要がある
			req_send = npc_mv | inReqSubDemo;

			OS_Printf("ポケ再動エフェクト\n");
			ChangeEndAnm(run_poke, inNetID, inRunPokeIdx, outChildData, req_send, inReqSubDemo);
		}
		PkthlnClAct_SetPos(run_poke->SmogActPtr, &t_vec);	//煙は常にポケの位置に。
		break;
	}
}

//--------------------------------------------------------------------------------------------
/**
 * パラメータセット
 *
 * @param	work		ポケスロンワークポインタ
 * @param	*inData		パラメータ
 * @param	inNetID		ネットＩＤ
 * @param	inIdx		ポケモンエントリーインデックス0〜2
 * @param	*outPoke	パラメータ格納場所
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetPokeParam(	PKTHLN_PTR work, const RUN_PARAM *inData,
							const u8 inNetID, const u8 inIdx, RUN_POKE *outPoke)
{
	const POKE_SPEC *spec;
	spec = PTFrame_GetPokeSpec(work, inNetID, inIdx);

	OS_Printf("%d::pw:st:sp = %d,%d,%d\n%d,%d,%d,%d,%d\n",
			inIdx,inData->Power[spec->Power],inData->Stamina[spec->Stamina],inData->Speed[spec->Speed],
			inData->SpeedMat[spec->Speed],inData->SpeedLow[spec->Speed],
			inData->Accel1[spec->Technique],inData->Accel2[spec->Speed],
			inData->Panic[spec->Stamina]);

	outPoke->Param[inIdx].Power = (float)inData->Power[spec->Power]/10.0;
	outPoke->Param[inIdx].StaminaMax = inData->Stamina[spec->Stamina];
	outPoke->Param[inIdx].Stamina = inData->Stamina[spec->Stamina];
	outPoke->Param[inIdx].SpeedMax = inData->Speed[spec->Speed];
	outPoke->Param[inIdx].SpeedMatMax = inData->SpeedMat[spec->Speed];
	outPoke->Param[inIdx].SpeedLowMax = inData->SpeedLow[spec->Speed];
	outPoke->Param[inIdx].Accel1 = (float)inData->Accel1[spec->Technique]/10.0;
	outPoke->Param[inIdx].Accel2 = (float)inData->Accel2[spec->Speed]/10.0;
	outPoke->Param[inIdx].PanicTime = inData->Panic[spec->Stamina];

}



//当たり判定
//
//画面内障害物の列挙そのほかの障害物は当たり亜判定から除外	---
//
//対象障害物の線分情報を取得・算出　４本出てくるはず ---
//
//境界ボリュームを考え、線分をシフト ---
//
//頂点情報を取得４つあるはず ---
//
//線分の交点を求める
//
//その交点は、線分上にあるか？
//ある場合は、次の移動先をその頂点にする
//
//４回繰り返す
//
//線分でヒットしていなかった場合頂点ヒットを行う
//
//ヒット中心点と移動先線分を結ぶ線分が、円1/4と交点を持つかを調べる
//交点を持つ場合、その交点が移動先となる
//
//
//円1/4との交点の求め方
//
//ちょっと手を抜く。交点の最大数は２つなので、はじめに引っかかった方を交点とする。
//1/4チェックの仕方。
//3/4でのヒットをはじかなければならないが、はじめに線分判定していれば、この3/4でのヒットは消せる
//なので、線分、円の順番で、行えば、円でのヒッチを行ってヒットした場合は、1/4でのヒットとみなせる
//（3/4でヒットしているならば、線分でのヒットもしてるはずということ
//
//交点でのヒットを検出したら、次の判定は、跳ね返りなので、２シンクに渡りヒッチは行わない。フラグをもって対処する。
//
//Ｎシンクに渡りあたりが検出された場合は、めり込みとかいろいろ見た目によろしくないことになっているはずなので、
//対処する。基本的には、同じ障害物には立て続けに当たらないことをキーにして、何か対策を（余裕があれば・・・）

//万一矩形内に入ってしまった場合は、障害物中心と自分中心の差分を取って、ＸＹ小さい方向に一気に押し出すようにする。

//--------------------------------------------------------------------------------------------
/**
 * 衝突判定すべき障害物のリストを作成する
 *
 * @param 	ptr				競技ポインタ
 * @param	inX				X座標
 * @param	outObstList		障害物リスト
 * @param	outMatList		砂利リスト
 * @param	outObstNum		障害物数
 * @param	outMatNum		砂利数
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void MakeObstList(PKTHLN_RUN_PTR ptr, const fx32 inX,
		int **outObstList, int **outMatList, u8 *outObstNum, u8 *outMatNum)
{
	int i;
	int my_len;
	//リストのクリア
	for(i=0;i<OBST_NUM_MAX;i++){
		outObstList[i] = NULL;
		outMatList[i] = NULL;
	}

	//リストカウンタ初期化
	*outObstNum = 0;
	*outMatNum = 0;
	my_len = inX / FX32_ONE;

	//全障害物の座標を見て描画するかを決める
	for(i=0;i<OBST_NUM_MAX;i++){
		//障害物データ取得
		if (ptr->Obst[i].Valid){
			VecFx32 vec;
			u8 type;
			u16 x,y;
			int disp_x;
			int len;
			type = ptr->ObstData[i] & 0xff;
			//相対距離を算出
			x = ptr->Obst[i].X;
//			y = ptr->Obst[i].Y;
			len = my_len - x;
			//画面表示位置を算出
			if (len >= ROUND_LEN-256){
				//周回距離（0〜1023）が自分の方が多く、差分が1周-1画面分ある場合は自分よりも前に描画する必要がある
				disp_x = START_POKE_POS_X + (ROUND_LEN-len);
			}else if(len <= -(ROUND_LEN-256)){
				//周回距離（0〜1023）が相手の方が多く,差分が1周-1画面分ある場合は自分よりも後ろに描画する必要がある
				disp_x = START_POKE_POS_X - (ROUND_LEN+len);
			}else{
				disp_x = START_POKE_POS_X - len;
			}
			//表示範囲内かを判断
			if((DISP_X_MIN <= disp_x)&&(disp_x <= DISP_X_MAX)){		//画面内
				//リストに追加
				if (type == OBST_MAT){
					outMatList[(*outMatNum)++] = &ptr->ObstData[i];
				}else{
					outObstList[(*outObstNum)++] = &ptr->ObstData[i];
				}
			}
		}else{
			break;
		}
	}

#ifdef PM_DEBUG
	if (debug_print){
		OS_Printf("判定する障害物の数は%d個\n",*outObstNum);
		OS_Printf("判定する砂利の数は%d個\n",*outMatNum);
		for(i=0;i<*outObstNum;i++){
			u8 y;
			u16 x;
			u8 type;
			type = (*outObstList[i]) & 0xff;
			y = ((*outObstList[i]) >> 8) & 0xff;
			x = ((*outObstList[i]) >> 16) & 0xffff;
			OS_Printf("check_obst = %d_%d_%d\n",type, x, y);
		}
		for(i=0;i<*outMatNum;i++){
			u8 y;
			u16 x;
			u8 type;
			type = (*outMatList[i]) & 0xff;
			y = ((*outMatList[i]) >> 8) & 0xff;
			x = ((*outMatList[i]) >> 16) & 0xffff;
			OS_Printf("check_mat = %d_%d_%d\n",type, x, y);
		}
	}
#endif
}

typedef struct SEG_tag
{
	Vec2DS32 Srt;
	Vec2DS32 End;
}SEG;

typedef struct OBST_HIT_DATA_tag
{
	OBST_TYPE Type;
	Vec2DS32 Vrt[4];
	SEG Seg[4];
}OBST_HIT_DATA;

//--------------------------------------------------------------------------------------------
/**
 * 障害物の衝突データを作成
 *
 * @param 	inRange			当たり範囲
 * @param	inObstData		障害物データ
 * @param	outHitData		衝突データ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void MakeHitData( const int inRange, const int *inObstData, OBST_HIT_DATA *outHitData)
{
	u8 type;
	u32 y;
	u32 x;
	u32 width;
	u32 range;
	type = (*inObstData) & 0xff;
	y = ((*inObstData) >> 8) & 0xff;
	x = ((*inObstData) >> 16) & 0xffff;

	y += INNER_OFS;

	range = inRange/* * FX32_ONE*/;
#ifdef PM_DEBUG
	if (debug_print){
		OS_Printf("check_obst = %d_%d\n",x, y);
	}
#endif

	//タイプ格納
	outHitData->Type = type;
	if (type == OBST_MAT){	//障害物が壁でなければ、左上座標だけ格納
//		OS_Printf("砂利\n");
		outHitData->Vrt[0].x = x - (OBST_MAT_WIDTH/2);
		outHitData->Vrt[0].y = y - (OBST_MAT_WIDTH/2);
		return;
	}else{
		//障害物幅を決定
		if (type == OBST_WALL_L){
			width = OBST_WALL_L_WIDTH/**FX32_ONE*/;
		}else{
			width = OBST_WALL_S_WIDTH/**FX32_ONE*/;
		}
		x -= (width/2);
		y -= (width/2);
		//4頂点格納
		outHitData->Vrt[0].x = x;
		outHitData->Vrt[0].y = y;
		outHitData->Vrt[1].x = x+width;
		outHitData->Vrt[1].y = y;
		outHitData->Vrt[2].x = x+width;
		outHitData->Vrt[2].y = y+width;
		outHitData->Vrt[3].x = x;
		outHitData->Vrt[3].y = y+width;
		//4線分格納
		outHitData->Seg[0].Srt = outHitData->Vrt[0];
		outHitData->Seg[0].End = outHitData->Vrt[1];
		outHitData->Seg[1].Srt = outHitData->Vrt[1];
		outHitData->Seg[1].End = outHitData->Vrt[2];
		outHitData->Seg[2].Srt = outHitData->Vrt[2];
		outHitData->Seg[2].End = outHitData->Vrt[3];
		outHitData->Seg[3].Srt = outHitData->Vrt[3];
		outHitData->Seg[3].End = outHitData->Vrt[0];
		//境界ボリューム分の足しこみ
		outHitData->Seg[0].Srt.y -= range;
		outHitData->Seg[0].End.y -= range;
		outHitData->Seg[1].Srt.x += range;
		outHitData->Seg[1].End.x += range;
		outHitData->Seg[2].Srt.y += range;
		outHitData->Seg[2].End.y += range;
		outHitData->Seg[3].Srt.x -= range;
		outHitData->Seg[3].End.x -= range;
	}
#ifdef PM_DEBUG
	if (debug_print){
		int i;
		OS_Printf("境界ボリュームを加味した結果\n");
		for(i=0;i<4;i++){
			OS_Printf("VERT%d = (%d,%d)\n", i,
					outHitData->Vrt[i].x, outHitData->Vrt[i].y);
			OS_Printf("SEG%d = (%d,%d)>(%d,%d)\n", i,
					outHitData->Seg[i].Srt.x, outHitData->Seg[i].Srt.y,
					outHitData->Seg[i].End.x, outHitData->Seg[i].End.y);
			OS_Printf("DIGI_SEG%d = (%d,%d)>(%d,%d)\n", i,
					outHitData->Seg[i].Srt.x/*/FX32_ONE*/, outHitData->Seg[i].Srt.y/*/FX32_ONE*/,
					outHitData->Seg[i].End.x/*/FX32_ONE*/, outHitData->Seg[i].End.y/*/FX32_ONE*/);
		}
	}
#endif
}

//--------------------------------------------------------------------------------------------
/**
 * 障害物との衝突
 *
 * @param	inSrt			開始座標
 * @param	inEnd			終端座標
 * @param 	inRange			当たり範囲
 * @param	inHitData		衝突データ
 * @param	outCross		交点座標
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static HIT_RC HitObst(const VecFx32 *inSrt, const VecFx32 *inEnd, const int inRange,
		const OBST_HIT_DATA *inHitData, VecFx32 *outCross )
{
	int i;
	Vec2DS32 cross;

	if (inHitData->Type == OBST_MAT){	//障害物が砂利床
		return HIT_RC_NONE;
	}else{								//障害物が壁
		Vec2DS32 srt,end;
		srt.x = inSrt->x/FX32_ONE;
		srt.y = inSrt->y/FX32_ONE;
		end.x = inEnd->x/FX32_ONE;
		end.y = inEnd->y/FX32_ONE;
		//線分交差判定
		for (i=0;i<4;i++){
			const HIT_RC hit_rc[4] = {HIT_RC_UWALL, HIT_RC_RWALL, HIT_RC_DWALL, HIT_RC_LWALL};
			int rc;
			rc = CheckCrossMatrix(
					(Vec2DS32 *)&inHitData->Seg[i].Srt,
					(Vec2DS32 *)&inHitData->Seg[i].End,
					&srt, &end,
					&cross );
			if (rc){
				outCross->x = cross.x * FX32_ONE;
				outCross->y = cross.y * FX32_ONE;
				outCross->z = 0;

///				OS_Printf("hit_type = %d\n",hit_rc[i]);
				return hit_rc[i];
			}else{
				int hit = 0;
				//既に線分上にいるかを調べる
				if ( (i==0)&&(i==2) ){		//上or下
					if ( inHitData->Seg[i].Srt.y == srt.y ){
						s32 srt_x,end_x;
						if ( inHitData->Seg[i].Srt.x < inHitData->Seg[i].End.x ){
							srt_x = inHitData->Seg[i].Srt.x;
							end_x = inHitData->Seg[i].End.x;
						}else{
							srt_x = inHitData->Seg[i].End.x;
							end_x = inHitData->Seg[i].Srt.x;
						}
						if ( (srt_x <= srt.x)&&(srt.x <= end_x) ){
							hit = 1;
						}
					}
				}else{						//左or右
					if ( inHitData->Seg[i].Srt.x == srt.x ){
						s32 srt_y,end_y;
						if ( inHitData->Seg[i].Srt.y < inHitData->Seg[i].End.y ){
							srt_y = inHitData->Seg[i].Srt.y;
							end_y = inHitData->Seg[i].End.y;
						}else{
							srt_y = inHitData->Seg[i].End.y;
							end_y = inHitData->Seg[i].Srt.y;
						}
						if ( (srt_y <= srt.y)&&(srt.y <= end_y) ){
							hit = 1;
						}
					}
				}
				if (hit){
///					OS_Printf("線分上\n");
					*outCross = *inSrt;
					return hit_rc[i];
				}
			}
		}

		//頂点ヒット判定
		for (i=0;i<4;i++){
			const HIT_RC hit_rc[4] = {HIT_RC_LU_VRT, HIT_RC_RU_VRT, HIT_RC_RD_VRT, HIT_RC_LD_VRT};
			//ポケ中心と頂点の距離を求める
			VecFx32 vert, dif;
			fx32 len;
			fx32 t;
			vert.x = inHitData->Vrt[i].x*FX32_ONE;
			vert.y = inHitData->Vrt[i].y*FX32_ONE;
			vert.z = 0;

			VEC_Subtract( inEnd, &vert, &dif );
			len = VEC_Mag(&dif);
#ifdef PM_DEBUG
			if (debug_print){
				OS_Printf("len%d\n",len);
			}
#endif
			if (len <= inRange*FX32_ONE){
				VecFx32 dir, dst;
///				OS_Printf("頂点ヒット\n");
				t = CalcT(inSrt, inEnd, &vert , inRange*FX32_ONE);
				VEC_Subtract( inEnd, inSrt, &dir );
				VEC_MultAdd(t,&dir,inSrt,&dst);
				outCross->x = dst.x;
				outCross->y = dst.y;
				outCross->z = 0;
///				OS_Printf("hit_type = %d\n",hit_rc[i]);
				return hit_rc[i];
			}
		}

		//矩形内ヒット判定
		if ( (inHitData->Vrt[0].x*FX32_ONE<=inEnd->x)&&(inEnd->x<=inHitData->Vrt[2].x*FX32_ONE) &&
			 (inHitData->Vrt[0].y*FX32_ONE<=inEnd->y)&&(inEnd->y<=inHitData->Vrt[2].y*FX32_ONE) ){

			HIT_RC rc;
			fx32 len1, len2;
			fx32 len_x, len_y;
			u8 h_hit,w_hit;
			u8 w, h;

			*outCross = *inEnd;
			h_hit = 0;
			w_hit = 0;

///			OS_Printf("矩形内。押し出します\n");
			len1 = inHitData->Vrt[0].x*FX32_ONE - inEnd->x;
			len2 = inHitData->Vrt[2].x*FX32_ONE - inEnd->x;
			if (len1<0) len1*=(-1);
			if (len2<0) len2*=(-1);
			if (len1<len2){
				len_x = len1;
				//左あたり
				w = HIT_RC_LWALL_F;
			}else{
				len_x = len2;
				//右あたり
				w = HIT_RC_RWALL_F;
			}

			len1 = inHitData->Vrt[0].y*FX32_ONE - inEnd->y;
			len2 = inHitData->Vrt[2].y*FX32_ONE - inEnd->y;
			if (len1<0) len1*=(-1);
			if (len2<0) len2*=(-1);
			if (len1<len2){
				len_y = len1;
				//上あたり
				h = HIT_RC_UWALL_F;
			}else{
				len_y = len2;
				//下あたり
				h = HIT_RC_DWALL_F;
			}

			if ( len_x<=len_y){
				//横あたり
				w_hit = 1;
				rc = w;
			}else{
				//縦あたり
				h_hit = 1;
				rc = h;
			}
			if (w_hit){
				if (w==HIT_RC_LWALL_F){
					outCross->x = (inHitData->Vrt[0].x-inRange)*FX32_ONE;
				}else{
					outCross->x = (inHitData->Vrt[2].x+inRange)*FX32_ONE;
				}
			}else if (h_hit){
				if (h==HIT_RC_UWALL_F){
					outCross->y = (inHitData->Vrt[0].y-inRange)*FX32_ONE;
				}else{
					outCross->y = (inHitData->Vrt[2].y+inRange)*FX32_ONE;
				}
			}
			return rc;
		}

	}

	return HIT_RC_NONE;
}

//--------------------------------------------------------------------------------------------
/**
 * 砂利とのヒット
 *
 * @param	inSrt			開始座標
 * @param	inHitData		衝突データ
 *
 * @return	BOOL			TRUEでヒット
 */
//--------------------------------------------------------------------------------------------
static BOOL HitMat(const VecFx32 *inSrt, const OBST_HIT_DATA *inHitData)
{
	fx32 x,y;
	fx32 mx,my;
	fx32 width;

	x = inSrt->x;
	y = inSrt->y;
	mx = inHitData->Vrt[0].x * FX32_ONE;
	my = inHitData->Vrt[0].y * FX32_ONE;
	width = OBST_MAT_WIDTH * FX32_ONE;

	if ( (mx < x)&&(x < mx+width) && (my < y)&&(y < my+width)	){
		return TRUE;
	}

	return FALSE;
}

//--------------------------------------------------------------------------------------------
/**
 * 障害物との衝突
 *
 * @param	ptr				競技ポインタ
 * @param	inHitRc			ヒットコード
 * @param	inRange			当たり範囲
 * @param	inSrt			開始座標
 * @param	inEnd			終端座標
 * @param	outVec			交点座標
 *
 * @return	u16
 */
//--------------------------------------------------------------------------------------------
static u16 HitCheckObst(PKTHLN_RUN_PTR ptr, const HIT_RC inHitRc, const int inRange,
		const VecFx32 *inSrt, const VecFx32 *inEnd, VecFx32 *outVec)
{
	u16 rc;
	int i;
	u8 obst_num;
	u8 mat_num;
	int *obst_list[OBST_NUM_MAX];
	int *mat_list[OBST_NUM_MAX];

	u8 mat_hit;
	u8 obst_hit;

#ifdef DEBUG_HIT_CHECK_IGNORE
	return 0;
#endif
#ifdef PM_DEBUG
	if (debug_print){
		OS_Printf("move_dir=(%d,%d)>(%d,%d)\n",
				inSrt->x/FX32_ONE, inSrt->y/FX32_ONE, inEnd->x/FX32_ONE, inEnd->y/FX32_ONE);
	}
#endif
	//障害物リスト作成
	MakeObstList(ptr, inSrt->x, obst_list, mat_list, &obst_num, &mat_num);

	//作成したリストの砂利と当たり判定を行う
	mat_hit = 0;
	for(i=0;i<mat_num;i++){
		OBST_HIT_DATA hit_data;
		HIT_RC hit_rc;
		//あたりデータを作成
		MakeHitData( inRange, mat_list[i], &hit_data);

		//砂利内判定
		if ( HitMat(inSrt, &hit_data) ){
			mat_hit = HIT_RC_MAT;
			break;
		}
	}

	//作成したリストの障害物と当たり判定を行う
	obst_hit = 0;
	for(i=0;i<obst_num;i++){
		OBST_HIT_DATA hit_data;

		HIT_RC hit_rc;
		VecFx32 cross;
		//あたりデータを作成
		MakeHitData( inRange, obst_list[i], &hit_data);

		//ヒット判定
		hit_rc = HitObst(inSrt, inEnd, inRange, &hit_data, &cross );

		if (hit_rc != HIT_RC_NONE){
///			OS_Printf("hit::type=%d  pos =(%d,%d)\n",hit_rc, cross.x, cross.y);
			if (HIT_RC_UWALL_F <= hit_rc ){
				outVec->x = cross.x;
				outVec->y = cross.y;
				outVec->z = 0;
			}else if (hit_rc != inHitRc){
				outVec->x = cross.x;
				outVec->y = cross.y;
				outVec->z = 0;
			}
			obst_hit = hit_rc;
			break;
		}
	}

	rc = (mat_hit << 8) + obst_hit;

	return rc;

}

//--------------------------------------------------------------------------------------------
/**
 * 媒介変数ｔを求める関数(tは値の小さい方を求める。マイナスにはならないはず)
 *
 * @param	inSrt			開始座標
 * @param	inEnd			終端座標
 * @param	inVrt			頂点
 * @param	inC				変数
 *
 * @return	fx32			媒介変数
 */
//--------------------------------------------------------------------------------------------
static fx32 CalcT(const VecFx32 *inSrt, const VecFx32 *inEnd, const VecFx32 *inVrt , const fx32 inC)
{
	fx32 a,b,c;
	fx32 len;
	fx32 sqrt;
	VecFx32 vec;

	fx32 t1,t2, t;

	VEC_Subtract( inEnd, inSrt, &vec );
	len = VEC_Mag(&vec);
	a = len*len;

	b = VEC_DotProduct(&vec, inVrt);

	len = VEC_Mag(inVrt);
	c = (len*len) - (inC*inC);

///	OS_Printf("abc = %d,%d,%d\n", a,b,c);

	sqrt = FX_Sqrt( b-(a*c) );
	t1 = -b + sqrt;
	t1 = FX_Div(t1,a);

	t2 = -b - sqrt;
	t2 = FX_Div(t2,a);

///	OS_Printf("sqrt = %d,%d\n", t1,t2);

	if (t1 > t2){
		t = t2;
	}else{
		t = t1;
	}

	return t;
}

//--------------------------------------------------------------------------------------------
/**
 * 最大スピードを求める
 *
 * @param	poke			競技ポケモン
 * @param	inRunPokeIdx	走行ポケモンインデックス
 *
 * @return	float			スピード
 */
//--------------------------------------------------------------------------------------------
static float GetMaxSpeed( RUN_POKE *poke, const u8 inRunPokeIdx )
{
	if (poke->MatOn){		//砂利の上
		return poke->Param[inRunPokeIdx].SpeedMatMax;
	}else if(poke->Param[inRunPokeIdx].Stamina <= FATIGUE_START){				//疲労状態
		return poke->Param[inRunPokeIdx].SpeedLowMax;
	}else{
		return poke->Param[inRunPokeIdx].SpeedMax;
	}
}

//--------------------------------------------------------------------------------------------
/**
 * Ｙ軸方向の切り替えしをすばやくできるような、スピード加算関数
 *
 * @param	inSrtVec			開始座標
 * @param	inAddVec			加算値
 * @param	outDstVec			算出ベクトル格納バッファ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void AddSpeedVec(const VecFx32 *inSrcVec, const VecFx32 *inAddVec, VecFx32 *outDstVec)
{
	//Ｘ軸は普通に加算
	outDstVec->x = inSrcVec->x + inAddVec->x;
	//Ｙ軸は、方向が同じならば加算、逆ならば上書き
	if ( FX_Mul(inSrcVec->y,inAddVec->y) >= 0 ){
		outDstVec->y = inSrcVec->y + inAddVec->y;
	}else{
		outDstVec->y = inAddVec->y;
	}
}

//--------------------------------------------------------------------------------------------
/**
 * ポケ同士の衝突
 *
 * @param	work				ポケスロンワークポインタ
 * @param	pPokeList			競技ポケモンリスト
 * @param	outVec				算出ベクトル格納バッファ
 *
 * @return	BOOL				TRUEでヒット
 */
//--------------------------------------------------------------------------------------------
static BOOL HitCheckPoke(PKTHLN_PTR work, RUN_POKE*	pPokeList, VecFx32 *outVec)
{
	int i,j;
	VecFx32 my_vec;
	VecFx32 target_vec;
	int my_range, target_range;
	POKE_ACT_PTR m_poke_ptr,  t_poke_ptr;
	BOOL hit_effect;

	hit_effect = FALSE;
	my_vec.z = 0;
	target_vec.z = 0;
	for(i=0;i<ENTRY_MEMBER_NUM_MAX;i++){
		RUN_POKE *my_poke;
		int msx_org, msy;
		u8 my_idx;

		my_poke = &pPokeList[i];
		my_idx = my_poke->RunPokeIdx;

		//自分が交代中ならスルー
		if(my_poke->ChgFlg){
			continue;
		}
		//ヒットポーズ中の場合はスルー
		if (my_poke->HitFrame){
			continue;
		}

		m_poke_ptr = my_poke->PokeActPtr[my_idx];
		PokeAct_GetTouchPosByShadowPos(m_poke_ptr, my_poke->Pos.x/FX32_ONE, my_poke->Pos.y/FX32_ONE, &msx_org, &msy);

		for(j=0;j<ENTRY_MEMBER_NUM_MAX;j++){
			RUN_POKE *target_poke;
			int tsx,tsy,msx;
			fx32 len, range;
			VecFx32 vec;

			RUN_POKE *atk_poke;
			RUN_POKE *dmg_poke;

			if (i==j){		//自分同士は当たり判定しない
				continue;
			}

			target_poke = &pPokeList[j];

			//対象相手が交代中ならスルー
			if(target_poke->ChgFlg){
				continue;
			}

			msx = msx_org;

			t_poke_ptr = target_poke->PokeActPtr[target_poke->RunPokeIdx];

			PokeAct_GetTouchPosByShadowPos(t_poke_ptr,
					target_poke->Pos.x/FX32_ONE, target_poke->Pos.y/FX32_ONE, &tsx, &tsy);

			//自分と相手が、スタートラインをまたぐ場合、相手のＸ座標を補正して当たり判定する
			if ( (my_poke->Pos.x > (ROUND_LEN-DISP_W)*FX32_ONE)&&(target_poke->Pos.x < DISP_W*FX32_ONE) ){
///				OS_Printf("自分がゴール手前。相手がゴールの向こう\n");
				tsx += ROUND_LEN;
			}else if( (target_poke->Pos.x > (ROUND_LEN-DISP_W)*FX32_ONE)&&(my_poke->Pos.x < DISP_W*FX32_ONE) ){
///				OS_Printf("相手がゴール手前。自分がゴールの向こう\n");
				msx += ROUND_LEN;
			}
			PokeAct_GetHitData(t_poke_ptr,
				tsx*FX32_ONE, tsy*FX32_ONE, &target_vec.x, &target_vec.y, &target_range);
			PokeAct_GetHitData(m_poke_ptr,
				msx*FX32_ONE, msy*FX32_ONE, &my_vec.x, &my_vec.y, &my_range);

			VEC_Subtract( &target_vec, &my_vec, &vec );
			len = VEC_Mag(&vec);
			range = (target_range + my_range)*FX32_ONE;

///			OS_Printf("%dと%dを比較。len=%d:rabge=%d\n",i,j,len,range);

			if ( len < range ){
				if (!my_poke->Hit[j]){
					u8 idx;
					fx32 scalar;
					VecFx32 add = {0,0,0};

					//あたりに行ったポケとあたられたポケを調べる
					{
						//自分から相手の方向ベクトルと自分の移動ベクトルの内積が0より大きい場合、自分が当たる側となる
						fx32 dot = VEC_DotProduct(&vec, &my_poke->Speed);
						if (dot > 0){
							//自分当たる側
							atk_poke = my_poke;
							dmg_poke = target_poke;
						}else{
							continue;
#if 0
							//自分は当たられる側
							atk_poke = target_poke;
							dmg_poke = my_poke;
#endif
						}
					}

					if ( VEC_Mag(&atk_poke->Speed) != 0 ){
						//ヒット。あたられたポケはあったてきたポケのスピードをもらう
						idx = atk_poke->RunPokeIdx;
						scalar = atk_poke->Param[idx].Power * FX32_ONE;
						VEC_MultAdd( scalar, &atk_poke->Speed, &add, &dmg_poke->Speed );
						//ゲーム最大速度は超えないようにする
						{
							fx32 len;
							len = VEC_Mag(&dmg_poke->Speed);
							if ( len > GAME_MAX_SPEED*FX32_ONE ){		//超えた
								VecFx32 add = {0,0,0};
								//正規化後GAME_MAX_SPEED倍
								VEC_Normalize(&dmg_poke->Speed, &dmg_poke->Speed);
								VEC_MultAdd(GAME_MAX_SPEED*FX32_ONE, &dmg_poke->Speed,
											&add, &dmg_poke->Speed);
							}
						}
					}

					if (dmg_poke->Param[my_idx].FatState == POKE_ST_FATIGUE){		//疲労
						//スタミナを0にして、気絶させる
						dmg_poke->Param[my_idx].Stamina = 0;
						dmg_poke->Param[my_idx].FatState = POKE_ST_PANIC;
						//気絶カウンタセット
						dmg_poke->PanicCount = dmg_poke->Param[my_idx].PanicTime;
						//アクションポイント加算「失敗回数」
						PTFrame_AddActionPoint(	work, dmg_poke->NetID, dmg_poke->RunPokeIdx, ADD_TYPE_FAIL, 1 );
					}else if(dmg_poke->Param[my_idx].FatState == POKE_ST_PANIC){	//気絶
					}

#if 0
					scalar = dmg_poke->Param[my_idx].Power * FX32_ONE;
					OS_Printf("sc=%d::%f\n",scalar,dmg_poke->Param[my_idx].Power);
					VEC_MultAdd( scalar, &speed, &add, &target_poke->Speed );
					//ゲーム最大速度は超えないようにする
					{
						fx32 len;
						len = VEC_Mag(&target_poke->Speed);
						if ( len > GAME_MAX_SPEED*FX32_ONE ){		//超えた
							VecFx32 add = {0,0,0};
							//正規化後GAME_MAX_SPEED倍
							VEC_Normalize(&target_poke->Speed, &target_poke->Speed);
							VEC_MultAdd(GAME_MAX_SPEED*FX32_ONE, &target_poke->Speed,
										&add, &target_poke->Speed);
						}
					}
#endif		//仕様変更あった方はスピード０になる
					//あたった方のは停止状態
					{
						VecFx32 zero = {0,0,0};
						atk_poke->Speed = zero;
					}

					if (atk_poke->Param[idx].FatState == POKE_ST_FATIGUE){		//疲労
						//スタミナを0にして、気絶させる
						atk_poke->Param[idx].Stamina = 0;
						atk_poke->Param[idx].FatState = POKE_ST_PANIC;
						//気絶カウンタセット
						atk_poke->PanicCount = atk_poke->Param[idx].PanicTime;
						//アクションポイント加算「失敗回数」
						PTFrame_AddActionPoint(	work, atk_poke->NetID, atk_poke->RunPokeIdx, ADD_TYPE_FAIL, 1 );
					}

					GF_ASSERT(my_poke->Hit[j] == 0);
					GF_ASSERT(target_poke->Hit[i] == 0);
					//ヒット状態をON
					dmg_poke->Hit[j] = 1;
					atk_poke->Hit[i] = 1;

					//ヒットエフェクト座標を計算
					if (!hit_effect ){
						VecFx32 vec = {0,0,0};
						fx32 r;
						hit_effect = TRUE;
						//自分からターゲットへのベクトル
						VEC_Subtract(&target_vec, &my_vec, &vec);
						//正規化
						VEC_Normalize(&vec, &vec);
						//自分の半径倍する
						r = my_range*FX32_ONE;
						VEC_MultAdd(r,&vec,&my_vec,&vec);
						//Xが1024オーバーなら、補正
						if (vec.x >= ROUND_LEN*FX32_ONE){
							vec.x = vec.x - ROUND_LEN*FX32_ONE;
						}
						*outVec = vec;
					}

					//ヒットポーズ開始
					dmg_poke->HitFrame = HIT_FRAME_DMG;
					atk_poke->HitFrame = HIT_FRAME_ATK;
					OS_Printf("ポケヒット\n");

					//アクションポイント加算「体当たり」
					PTFrame_AddActionPoint(	work, dmg_poke->NetID, dmg_poke->RunPokeIdx, ADD_TYPE_ATTACK, 1 );
					PTFrame_AddActionPoint(	work, atk_poke->NetID, atk_poke->RunPokeIdx, ADD_TYPE_ATTACK, 1 );
					break;
				}
			}else{
				//ヒットしてないので、ヒット状態をＯＦＦ
/**
				if (my_poke->Hit[j]){
					OS_Printf("ヒットを解除%d_%d\n",i,j);
				}
				if (target_poke->Hit[i]){
					OS_Printf("ヒットを解除%d_%d\n",j,i);
				}
*/
				my_poke->Hit[j] = 0;
				target_poke->Hit[i] = 0;
			}
		}
	}

	return hit_effect;
}

//--------------------------------------------------------------------------------------------
/**
 * ステートアクターの表示位置を決定しセットする
 *
 * @param	inParam				ポケスロンポケモンパラムポインタ
 * @param	inSdwPos			影座標
 * @param	pStateActPtr		ステートアクタポインタ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetStateActPos(	const PKTHPOKE_PARAM *inParam,
							const VecFx32 *inSdwPos,
							PKTHLN_ACT_PTR pStateActPtr )
{
	VecFx32 vec;
	vec = *inSdwPos;

	//シャドータイプを取得
	switch(inParam->Shadow){
	case SHADOW_TYPE_A:
		vec.y -= (20*FX32_ONE);
		break;
	case SHADOW_TYPE_B:
		vec.y -= (32*FX32_ONE);
		break;
	case SHADOW_TYPE_C:
		vec.y -= (40*FX32_ONE);
		break;
	default:
		GF_ASSERT(0);
	}

	PkthlnClAct_SetPos(pStateActPtr, &vec);
}

//--------------------------------------------------------------------------------------------
/**
 * Ｙ座標から障害物プライオリティーを決定する
 *
 * @param	obst			障害物
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetObstPriority(RUN_OBST *obst)
{
	int ofs;
	int pri;
	//砂利ならプライオリティは固定
	if (obst->Type == OBST_MAT){
		PkthlnClAct_SetPriority(obst->ActPtr, 600);
		return;
	}
	//Ｙ座標でプライオリティを決定する
	ofs = OBST_Y_LIMIT - (obst->Y+INNER_OFS);
	if (ofs < 0){
		ofs = 0;
	}
	ofs /= 8;

	pri = PRI_BASE_OFS + ((ofs+1) * 30);

	PkthlnClAct_SetPriority(obst->ActPtr, pri);

	OS_Printf("obst_pri = %d\n",pri);


}

//--------------------------------------------------------------------------------------------
/**
 * ポケのプライオリティセット
 *
 * @param	poke			競技ポケモン
 * @param	inY				Y座標
 * @param 	inMine			自分のポケモンか？
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void SetPokePriority(RUN_POKE *poke, const u8 inY, const BOOL inMine)
{
	int ofs;
	int pri;
	int i;
	//Ｙ座標でプライオリティを変更
	ofs = Y_LIMIT - inY;
	if (ofs < 0){
		ofs = 0;
	}

	ofs /= 8;

	if (inMine){
		pri = PRI_BASE_OFS+1 + ofs*30;
	}else{
		pri = PRI_BASE_OFS+4 + ofs*30;
	}

	//煙
	PkthlnClAct_SetPriority(poke->SmogActPtr, pri);
	//ブースト
	PkthlnClAct_SetPriority(poke->BoostActPtr, pri+1);
	//ステート
	PkthlnClAct_SetPriority(poke->StateActPtr, pri+1);
	//ボール
	PkthlnClAct_SetPriority(poke->ChgBallActPtr, pri+2);
	//ポケ
	for(i=0;i<ENTRY_MAX;i++){
		PokeAct_SetPriority(poke->PokeActPtr[i], pri+2);
	}
/**
	if (inMine){
		OS_Printf("poke_pri = %d\n",pri+2);
	}
*/
}

//--------------------------------------------------------------------------------------------
/**
 * ゴールラインのフィル
 *
 * @param	bgl			BGL
 * @param 	inLen		走行距離
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void FillGoalLine(GF_BGL_INI *bgl, const int inLen)
{
	int posx = START_POKE_POS_X/8;

	if ((256+16 < inLen)&&(inLen<768)){
		GF_BGL_ScrFill( bgl, GF_BGL_FRAME0_M, 1, posx, 3, 2, 21, GF_BGL_SCRWRT_PALNL );
	}else{
		GF_BGL_ScrFill( bgl, GF_BGL_FRAME0_M, 32, posx, 3, 2, 21, GF_BGL_SCRWRT_PALNL );
	}
	GF_BGL_LoadScreenV_Req(bgl, GF_BGL_FRAME0_M);
}

//--------------------------------------------------------------------------------------------
/**
 * LAPの表示
 *
 * @param	pLapAct		「LAP」アクター
 * @param 	inLap		現在ラップ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void DispLap(LAP_ACT *pLapAct, const u8 inLap)
{
	u8 t,o;
	BOOL disp;
	VecFx32 vec = {0,96*FX32_ONE,0};
	VecFx32 vec_n1 = {0,96*FX32_ONE,0};
	VecFx32 vec_n2 = {0,96*FX32_ONE,0};

	//保存しているラップを上回った場合に処理
	if (pLapAct->StockLap < inLap){
		pLapAct->StockLap = inLap;
		disp = TRUE;
	}else{
		disp = FALSE;
	}

	if (disp){		//表示リクエスト
		//座標決定
		t = inLap / 10;
		o = inLap % 10;
		if (t != 0){		//ラップが二桁
			vec.x = (128-32)*FX32_ONE;
			vec_n1.x = (128+16)*FX32_ONE;
			vec_n2.x = (128+48)*FX32_ONE;
			CLACT_AnmChg(pLapAct->LapNum1Ptr, t+1);
			CLACT_AnmChg(pLapAct->LapNum2Ptr, o+1);
		}else{				//ラップが一桁
			vec.x = (128-16)*FX32_ONE;
			vec_n1.x = (128+32)*FX32_ONE;
			CLACT_AnmChg(pLapAct->LapNum1Ptr, o+1);
			CLACT_AnmChg(pLapAct->LapNum2Ptr, 0);
		}
		PkthlnClAct_SetPos(pLapAct->LapActPtr, &vec);
		CLACT_SetMatrix(pLapAct->LapNum1Ptr, &vec_n1);
		CLACT_SetMatrix(pLapAct->LapNum2Ptr, &vec_n2);

		//表示
		PkthlnClAct_SetActive(pLapAct->LapActPtr, 1, 1);
		CLACT_SetDrawFlag(pLapAct->LapNum1Ptr, 1);
		CLACT_SetDrawFlag(pLapAct->LapNum2Ptr, 1);
		pLapAct->Timer = LAP_DISP_TIME;		//表示時間セット

		//ラップ表示ＳＥ
		Snd_SePlay( SE_THLON_POINT3 );
	}else{				//表示カウンタの減算
		pLapAct->Timer--;
		if (pLapAct->Timer<=0){
			pLapAct->Timer = 0;
			//非表示にする
			PkthlnClAct_SetActive(pLapAct->LapActPtr, 1, 0);
			CLACT_SetDrawFlag(pLapAct->LapNum1Ptr, 0);
			CLACT_SetDrawFlag(pLapAct->LapNum2Ptr, 0);
		}
	}
}

//----------レコードＢＭＰ---------------
//ＢＮＰウィンドウデータ
static const BMPWIN_DAT RecordBmpData = {
		REC_BG, WIN_REC_PX, WIN_REC_PY,
		WIN_REC_SX, WIN_REC_SY, REC_FONT_PAL, WIN_REC_CGX
};

//--------------------------------------------------------------------------------------------
/**
 * BMPウィンドウ追加
 *
 * @param 	ptr			コントローラポインタ
 *
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void CreateBmpWin( PKTHLN_RUN_PTR ptr )
{
	const BMPWIN_DAT * dat = &RecordBmpData;

	GF_BGL_BmpWinAddEx( ptr->bgl, &ptr->Win, dat );

	//先頭キャラをクリア（スクリーンクリアされてるところは、このキャラで埋まる）
	GF_BGL_CharFill( ptr->bgl, REC_BG, 0, 1, 0 );

	//システム用フォントパレット転送
	SystemFontPaletteLoad(PALTYPE_MAIN_BG, REC_FONT_PAL*32, ptr->HeapID);
}

//----------------------------------------------------------------------------
/**
 *	@brief		レコード文字列展開
 *
 *	@param	ptr		コントローラポインタ
 *	@param	inRound	周回数
 *	@param	inLen	１週に満たない距離
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void SetRecordStr(PKTHLN_RUN_PTR ptr, const int inRound, const u16 inLen)
{
	WORDSET *word;
	STRBUF * str;
	MSGDATA_MANAGER *msgman;
	int integer;
	int decimal;

	GF_BGL_BmpWinDataFill( &ptr->Win, 0);

	//整数部分
	integer = inRound;
	//小数部分
	decimal = (inLen*10)/ROUND_LEN;
	GF_ASSERT(decimal<=9);

	msgman = MSGMAN_Create(MSGMAN_TYPE_DIRECT, ARC_MSG, NARC_msg_pokethlon_dat, ptr->HeapID);
    word = WORDSET_Create(ptr->HeapID);
	WORDSET_RegisterNumber(word, 0, integer, 2,
				NUMBER_DISPTYPE_ZERO,NUMBER_CODETYPE_DEFAULT);
	WORDSET_RegisterNumber(word, 1, decimal, 1,
				NUMBER_DISPTYPE_ZERO,NUMBER_CODETYPE_DEFAULT);

    str = MSGDAT_UTIL_AllocExpandString(word, msgman, msg_pkthln_new_record07, ptr->HeapID);

	GF_STR_PrintColor( 	&ptr->Win, FONT_TOUCH, str,
					0, 0, MSG_NO_PUT, COL_N_WHITE, NULL );
	STRBUF_Delete(str);//<一括表示なので、メモリをここで消してもOK
	WORDSET_Delete( word );
	MSGMAN_Delete( msgman );

	GF_BGL_BmpWinOn(&ptr->Win);
}

//----------------------------------------------------------------------------
/**
 *	@brief		画面内判定つきＳＥ再生
 *
 *	@param	inX			Ｘ座標
 *	@param	inSE		SE
 *	@param	inMine		自分ならTRUE
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void PlaySeDispCheck(const int inX, const int inSE, const BOOL inMine)
{
	int se_player;

	if ( (0<=inX)&&(inX<256) ){
		if (inMine){
			se_player = SE_PLAYER_MINE;
		}else{
			se_player = SE_PLAYER_OTHERS;
		}
		Snd_SePlayEx( inSE, se_player );
	}
}

//----------------------------------------------------------------------------
/**
 *	@brief	交代ボタンステート決定
 *
 *	@param	ptr				競技ポインタ
 *	@param	inNetID			ネットＩＤ
 *	@param	inValid			ボタン矩形か？
 *
 *	@return	none
 */
//-----------------------------------------------------------------------------
static void SetBtnState(PKTHLN_RUN_PTR ptr, const u8 inNetID, const BOOL inValid)
{
	u8 *btn_st;
	u8 st;
	u8 fat_state;
	btn_st = &ptr->BtnSt[inNetID];
	st = BTN_ST_PUSH_OK;

	fat_state = ptr->Poke[inNetID].Param[ ptr->Poke[inNetID].RunPokeIdx ].FatState;

	//現在押せるのか押せないのか。
	if (ptr->Poke[inNetID].ChgFlg){		//交代中
		st = BTN_ST_PUSH_NG;
	}else if(ptr->Poke[inNetID].HitFrame){	//ヒットポーズ中
		st = BTN_ST_PUSH_NG;
	}else if( fat_state == POKE_ST_PANIC ){	//気絶中
		st = BTN_ST_PUSH_NG;
	}else if( fat_state == POKE_ST_FATIGUE ){	//疲労中
		st = BTN_ST_PUSH_OK_FLASH;
	}

	if (!inValid){
		//現在のステートで表示
		*btn_st = st;
		return;
	}

	if ( ptr->TpState[inNetID].Trg ){		//トリガー
		//現在のボタンステートを確認して押下ステートに移行
		if ((st == BTN_ST_PUSH_OK)||(st == BTN_ST_PUSH_OK_FLASH)){
			*btn_st = BTN_ST_PUSH_OK_PUSH;
		}else if(st == BTN_ST_PUSH_NG){
			*btn_st = BTN_ST_PUSH_NG_PUSH;
		}else{
			GF_ASSERT(0);
		}
	}else if ( ptr->TpState[inNetID].Cont ){	//ベタ
		//ステートが変わっても、リリースするまでは同じ見た目を保持する(つまり何もしない)
	}else{	//リリース
		//現在のステートで表示
		*btn_st = st;
	}
}

//--------------------------------------------------------------------------------------------
/**
 * レコードコールバック関数
 *
 * @param	work		ポケスロンワークポインタ
 * @return	none
 */
//--------------------------------------------------------------------------------------------
static void RecCallBack(PKTHLN_PTR work)
{
	COMM_EVENT_COMMON_DATA * data;
	RUN_PARENT_DATA *parent;
	PKTHLN_RUN_PTR ptr;

	data = PTFrame_GetEvtComCmnData(work);
	parent = PKTHLN_CommPack_GetData(&data->ReciveShareData);
	ptr = PTFrame_GetEventWorkPtr(work);

	//ニューレコード用にレコードをセット
	{
		u8 my_net_id;
		u8 round;
		u16 len;
		u16 total;
		my_net_id = PTFrameGetCurrentID(work);
		round = parent->St2[my_net_id] & 0x7f;		//7ビットマスク
		len = parent->PokeLen[my_net_id];
		//フレームワークにニューレコードチェック用のレコード値をセット
		if (round > ROUND_MAX){
			round = ROUND_MAX;
		}
		total = (round*ROUND_LEN_INT)+len;
		PTFrame_SetCheckRecord(work, total);
		SetRecordStr(ptr, round, len);
	}
}
